четверг, 30 мая 2013 г.

Вставка данных в таблицу, если запись в ней отсутствует. Oracle


INSERT INTO table
SELECT trunc(sysdate), 0
FROM dual
WHERE NOT EXISTS (
  SELECT NULL 
  FROM table
  WHERE day=trunc(sysdate)
);

вторник, 28 мая 2013 г.

Чем отличается абстрактный класс от интерфейса?

Казалось бы, этот вопрос задается на многих собеседованиях на вакансию Java-программиста, но многие на него почему-то не могут дать достойного ответа. Так в чем же отличие? Отличия эти подразделяются на два типа: семантические и идеологические. Первые определяет структуру, а второй - для какой цели.

В абстрактном классе может присутствовать реализация методов, конструкторов, переменных состояния, а так же объявление методов, которые должны быть реализованы наследниками. В интерфейсе не может быть реализации методов, он может содержать список методов, которые должны быть переопределены.

Один класс может напрямую наследовать только от одного абстрактного класса. Реализаций интерфейса может быть несколько для одного класса. Осносное назначеине - решение проблемы с множественным наследованием. Т.е. класс может быть одновременно нескольких типов. Так же интерфейс помогает избавиться от ромбовидного наследования

Абстрактный класс должен служить для определения общей функциональности объектов, а интерфейс должен описывать, через какие методы можно обращаться в объекту.

четверг, 16 мая 2013 г.

Как работает substring для объектов String в Java?

Как работает метод substring для объектов String в Java?

Ответ

Работа метода substring зависит от версии Java. Начиная с версии 7u6, после вызова метода substring создается новый объект String, через конструктор

public String(char value[], int offset, int count) {
    ...
    ...
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}
где char value[] исходный массив символов строки, offset - смещение и count - количество символов. Из кода видно, что создается новый массив, хранящий символы. В версиях до Java 7u6 дела обстоят иначе: так же создается новый объект String, но используется старый массив char value[].

// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}
Т.е. если исходная строка имеет очень большой размер, то создав короткий substring от нее, мы будем хранить в памяти большой массив из-за оставшейся на него ссылки. Это не позволяет сборщику мусора собрать оригинальную строку, из-за чего может возникнуть утечка памяти. Изначально это было сделано для ускорения создания подстрок, но было отмечено как баг и устранено в версии Java 7u6.

Чем отличается создание строки через new от создания через литерал?


String s1 = new String("test1");
String s2 = "test2";

Ответ

При создании строки через new, она не попадает в string pool. Что бы она туда попала, необходимо сделать s1.intern() или создать строку через литерал. String pool служит для того, что бы не создавались повторно существующие строки.

среда, 30 января 2013 г.

Что выведет программа?

int i = 0;
if (i == 1) if (i == 0) i = 10; else i = 20;
System.out.println(i);

Ответ

0
"Else" принадлежит к ближайшему "if" слева. В связи с возможностью неоднозначного понимания, рекомендуется расставлять скобки.

int i = 0;
if (i == 1) {
    if (i == 0) {
        i = 10;
    } else {
        i = 20;
    }
}
System.out.println(i);

суббота, 26 января 2013 г.

Бинарный поиск

Одним из основных алгоритмов поиска является бинарный поиск. Он работает только с отсортированными данными, за счет этого достигается большая скорость поиска: O(logN). Принцип работы алгоритма прост: находим середину массива данных, проверяем, больше, меньше и равно искомое значение значению в середине. Если равно, значит нашли. Если искомое больше, значит дальше ищем только в правой половине, если меньше - в левой. Т.е. с каждой итерацией количество данных для поиска делится надвое.

public class Binary {
    public static void main(String[] args) {
        int[] arr = { 1,12,23,34,55,61,67,88,89,101 };
        System.out.println(rank(55, arr));
    }
    
    public static int rank(int val, int[] arr) {
        return rank(val, arr, 0, arr.length-1);
    }
    
    private static int rank(int val, int[] arr, int lo, int hi) {
        if (lo > hi) return -1;
        
        int mid = lo + (hi - lo) / 2;
        
        if (val < arr[mid]) {
            return rank(val, arr, lo, mid - 1);
        } else if (val > arr[mid]) {
            return rank(val, arr, mid + 1, hi);
        } else {
            return mid;
        }
    }
}

понедельник, 21 января 2013 г.

Как проверить, является ли число простым

Простые числа являются элементарными строительными блоками натуральных чисел. Простые числа применяются, например, в криптографии. За нахождение простых чисел из более чем 100 000 000 и 1 000 000 000 десятичных цифр назначена премия в 150 000 и 250 000 долларов США, говорится в Википедии.

/**
 * Является ли число простым?
 */
public static boolean isPrime(int N) {
    if (N < 2) return false;
    for (int i = 2; i*i <= N; i++)
        if (N % i == 0) return false;
    return true;
}

воскресенье, 20 января 2013 г.

Умножение матриц

Умножение матриц - одна из основных операций над матрицами. Принцип умножения матриц хорошо описан в Википедии

В двумерном массиве arr[m][n], по соглашению, первое значение - количество строк, второе - столбцов.

Применение умножения матриц можно найти, например,при программировании поведения объектов в трехмерном пространстве.


public class MatrixMultiplection {
    public static void main(String[] args) {
        int[][] mA = 
            {{33,34,12},
             {33,19,10},
             {12,14,17},
             {84,24,51},
             {43,71,21}};
        
        int[][] mB = 
            {{10,11,34,55},
             {33,45,17,81},
             {45,63,12,16}};

        
        int m = mA.length;
        int n = mB[0].length;
        int o = mB.length;
        int[][] res = new int[m][n];
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < o; k++) {
                    res[i][j] += mA[i][k] * mB[k][j]; 
                }
            }
        }
        
        for (int i = 0; i < res.length; i++) {
            for (int j = 0; j < res[0].length; j++) {
                System.out.format("%6d ", res[i][j]);
            }
            System.out.println();
        }
    }
}
/**
  Output:   
  1992   2649   1844   4761 
  1407   1848   1565   3514 
  1347   1833    850   2066 
  3927   5217   3876   7380 
  3718   4991   2921   8452
 */

Данный алгоритм имеет сложность O(n3). Алгоритм Копперсмита — Винограда может делать это за O(n2.3727).

Выстраиваем элементы массива в обратном порядке


import java.util.Arrays;
/**
 * Меняет порядок элементов массива на обратный за n/2
 */
public class ReverseElements {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8,9,10,11};
        for (int i = 0; arr.length/2 > i; i++) {
            int tmp = arr[i];
            arr[i] = arr[arr.length - i - 1];
            arr[arr.length - i - 1] = tmp;
        }
        System.out.println(Arrays.toString(arr));
        
    }
}

Наибольший общий делитель


/**
 * Алгоритм Евклида. Наибольший общий делитель
 * */
public class GratestCommonDivisor {
    public static void main(String[] args) {
        System.out.println(gcd(30000, 1701));
    }
    
    public static int gcd(int a, int b) {
        if (b == 0) return a;
        int x = a % b;
        return gcd(b, x);
    }
}

среда, 15 августа 2012 г.

Вызываем метод

Всё ли в порядке в коде?

public void go()
{
    ripper(10,11,15,-1);
}

public void ripper(short... args)
{
    System.out.print(args.length);
} 

Ответ

Не скомпилируется
В метод ripper мы передаем int, ожидается short

Объявление массива

Скомпилируется ли?

Object hobject = new Short[4];

Ответ

Да
Каждый массив - это объект

Конструкторы

Что выведет программа?

class Test {
    public static void main(String[] args) {
        Devil dev = new Boast(1);
    }
}

class Boast extends Devil 
{
    public Boast(){System.out.print("boast ");}
    public Boast(int i)
    {}
}

class Devil
{
    public Devil(){System.out.print("devil ");}
    public Devil(int i)
    {}  
}

Ответ

devil
При создании объекта, всегда вызываются конструкторы по умолчанию у родителей, начиная с самого старшего.
Если в конструкторе вызывается конструктор родителя, то конструктор по умолчанию родителя не вызывается

вторник, 14 августа 2012 г.

Статические поля

Что выведет программа?

class T1 extends T {}

class T2 extends T {}

class T {
    public static int i;
}

public class Test {
    public static void main(String[] args) {
        T1.i = 5;
        T2.i = 3;
        System.out.format("%d = %d", T1.i, T2.i);
    }
}

Ответ

3 = 3
Статические поля родительских классов являются общими для наследников

Integer

Что выведет программа?

Integer i1 = Integer.valueOf(11);
Integer i2 = Integer.valueOf(11);
System.out.println(i1 == i2);
        
Integer i3 = Integer.valueOf(10000);
Integer i4 = Integer.valueOf(10000);
System.out.println(i3 == i4);

Ответ

true
false

Класс Integer содержит пул предопределенных объектов (-128...127)

Вызов методов из конструктора

Что выведет программа?

public class Parent {
    Parent() {
        test();
    }
    
    public static void main(String[] args) {
        new Child();
    }
 
    protected void test() {
     System.out.println("Hello from Parent");
    }
}

class Child extends Parent {
    private final String someString;
    Child() {
        someString = "some Text";
    }
    protected void test() {
        System.out.println("Hello from Child");
        System.out.println(someString);
    }
}

Ответ

Hello from Child
null

Если в конструкторе базового класса вызвать метод, который переопределен в дочернем, то при создании дочернего класса в конструкторе базового будет вызван метод дочернего класса, хотя очередь инициализации этого класса еще не настала. Это может привести к ошибкам. Например, вызванный метод может использовать переменные, которые еще не были инициализированы. Надо стараться избегать вызова методов в конструкторах. Можно смело вызывать только методы, помеченные в текущем классе как final или private, т.к. они не переопределяются.

Значение переменных внутри метода

Что выведет программа?

class Test {
    public static void main(String[] args) {
        String s = "old";
        print(s, s = "new");
    }
    
    static void print(String s1, String s2) {
        System.out.println(s1 + " " + s2);
    }
}

Ответ

old new
Внутри вызова метода значения присваиваются разным переменным

Finally

Какое значение вернет метод?

private static int foo() {
    int a = 1;
    int b = 2;
    try  {
        return a + b;
    } finally {
        a = 10;
        b = 20;
        return a + b;
    }
}

Ответ

30
Блок finally должен выполняться всегда, даже если в try есть return. Return внутри finally перебивает предыдущий return.

суббота, 11 августа 2012 г.

Операции с числами

Что выведет программа?

int x = 4;
System.out.println("value is " + ((x > 4) ? 99.99 : 9));

Ответ

value is 9.0
При выполнении сравнения между разными типами, типы приводятся к одному, если это возвожно

Сколько объектов в коллекции?

Что выведет программа?

public class Animal {
    private final String type;
    Animal(String type) {
       this.type = type; 
    }
    
    public boolean equals(Animal animal) {
        return type.equals(animal.type);
    }
    
    public int hashCode() {
        return type.hashCode();
    }

    
    public static void main(String[] args) {
        Set set = new HashSet();
        set.add(new Animal("Dog"));
        set.add(new Animal("Cat"));
        set.add(new Animal("Cat"));
        System.out.println(set.size());
    }
}

Ответ

3
Метод equals должен принимать объекты типа Object, а у нас - Animal. Из-за этого не произошло перезаписи метода и использовался метод equals класса Object. Что бы такого не просходило, надо всегда использовать аннотацию @Override в тех местах, где мы хотим переопределить метод.