Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Java, ну для чего?

Anna | 4.06.2014 | нет комментариев
Приветствую, высокочтимый читатель.
Java — увлекательный и прекрасный язык. Но изредка на нем дозволено написать такое, что отменнее этого не видеть. Но все равно благотворно знать, что происходит и в таких, кривых, случаях.
Любителей чистого кода умоляю меня простить.

Когда-то давным-давно на прогре была пара статей как не нужно писать на java с увлекательными задачками по java.
Часть 1Часть 2
Они дюже увлекательные, но, к сожалению, автор не стал продолжать.

Представляю вашему вниманию еще 2 задачки (на большее не хватило сил. Оказывается, писать статьи не так-то легко.)

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

Вторая задача взята напрочь из восхитительной книги Джошуа Блоха Java Puzzlers. Книга не обучит вас, как писать код (скорее напротив, как не нужно и отчего), но лично мне было дико увлекательно это читать. Легко для веселия. Рекомендую.

Выходит, приступим.

Данные

1. Казнить невозможно помиловать
public class A {
    public static class X {
        public static class Y {
            public static String Z = "life is good";
        }

        public static C Y;
    }

    public static class C {
        public static String Z = "life is pain";
    }

    public static void main(String[] args) {
        System.out.println(X.Y.Z);
    }
}

Что произойдет?

  1. Compile error
  2. Runtime error
  3. Выведет life is good
  4. Выведет life is pain

Помимо этого как, не меняя имен, [исправить ошибку, если результат 1/2 и] вывести обе строчки?

2. Дженерики такие дженерики
   public class B {
    public static <T> T foo() {
        try {
            return (T) new Integer(42);
        } catch (ClassCastException e) {
            return (T) "habr";
        }
    }
    public static void main(String[] args) {
        System.out.println(B.<String>foo());
    }
}

Что произойдет?

  1. Compile error
  2. Runtime error
  3. Выведет 42
  4. Выведет habr

А сейчас положительные результаты:

1. Казнить невозможно помиловать
public class A {
    public static class X {
        public static class Y {
            public static String Z = "life is good";
        }

        public static C Y;
    }

    public static class C {
        public static String Z = "life is pain";
    }

    public static void main(String[] args) {
        System.out.println(X.Y.Z);
    }
}

Выведет life is pain
Здесь все дико, но легко. Да, jls такое разрешает. Приоритет неизменно у поля.

Значительно увлекательнее — как это обойти и вывести-таки life is good? Мне вестимы три решения:

  • reflection api
  • импорт X.Y
  • К статике дозволено обращаться через экземпляр: (new X.Y()).Z
Задание на пятерку

Конечный метод отличен, но требует создания объекта, что нехорошо. Добавим приватный конструктор.А сейчас слабо? (без рефлексии и статического импорта)

    public static class X {
        public static class Y {
            private Y() {}
            public static String Z = "life is good";
        }

        public static C Y;
    }

Результат:

Спрятанный текст

    ((X.Y)null).Z; // подберите свои челюсти, это Java.
2. Дженерики такие дженерики
   public class B {
    public static <T> T foo() {
        try {
            return (T) new Integer(42);
        } catch (ClassCastException e) {
            return (T) "habr";
        }
    }
    public static void main(String[] args) {
        System.out.println(B.<String>foo());
    }
}

Runtime error

Выходит, все мы знаем, что в java дженерики — не больше чем синтаксический сахар, ограничивающий наши вероятности дозволяющий компилятору исполнять добавочные проверки типов. Но как только программа запущена — каждая информация о классах-параметрах теряется. Увы, это не c и даже не c#.

Посмотрим наблюдательно на код:

System.out.println(B.<String>foo());

Компилятор понимает, что тип довода — String, а следственно подставляет особенно подходящий println:

public void println(String x)

Значимо, что определять, какую версию перегруженного способа применять — задача яруса компиляции, не рантайма.

Идем дальше.

return (T) new Integer(42);

Cast происходит в рантайме, в тот момент, когда дженериков теснее «нет».
Что произойдет?
Ничего. Легко вернется Integer.

Ну и приехали — вызвали printf, принимающий String, а передали ему Integer.

Уроки на грядущее
  • Не нужно так делать
  • В мире есть не только println, принимающий Object
  • Каст к типу дженерика — это костыль
Задание на пятерку

Реализуйте способ, бросающий произвольный Throwable (в том числе, checked exception), не требующий ни thows, ни try-catch:

public static void throwWithoutCheck(Throwable t) {
    // Никаких проверок, только хардкор. Хочу throwWithoutCheck(new Exception()) - и никаких throws!
}

Результат:

Спрятанный текст

    private static <T extends Throwable> void castAndThrow(Throwable t) throws T {
        throw (T) t;
    }
    public static void throwWithoutCheck(Throwable t) {
        B.<RuntimeException>castAndThrow(t);
    }
 Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB