Приховані особливості Java


295

Прочитавши приховані особливості C #, я задумався, які існують приховані особливості Java?


17
Зауважте, що не завжди чудова ідея використовувати ці приховані функції; часто вони дивують і бентежать інших, хто читає ваш код.
Кевін Бурліон

1
Ви (/ хтось), ймовірно, повинні акуратно підсумувати відповіді в тілі питань, як питання C #.
ripper234

Відповіді:


432

Подвійна брекет-ініціалізація мене здивувала кілька місяців тому, коли я вперше виявив її, ніколи раніше про неї не чув.

Зазвичай ThreadLocals не настільки широко відомий як спосіб зберігання стану в потоці.

Оскільки JDK 1.5 Java має надзвичайно добре реалізовані та надійні інструменти одночасності, крім простого блокування, вони живуть у java.util.concurrent, а особливо цікавим прикладом є java.util.concurrent.atomic підпакет, який містить безпечні для потоків примітиви, які реалізують порівняння -і операція підкачки та може відображати фактичні підтримувані апаратними версіями цих операцій.


40
Подвійна дужка ініціалізація ... дивна ... Мені б насторожено сприймати цю особливу ідіому занадто широко, хоча вона фактично створює анонімний підклас об'єкта, що може спричинити заплутаність проблем рівності / хеш-коду. java.util.concurrent - це справді чудовий пакет.
МБ.

6
Я навчив Яву, і це я вперше зіткнувся з цим синтаксисом ... який показує, що ти ніколи не перестаєш вчитися = 8-)
Ювал,

49
Зауважте, що якщо ви зберігаєте посилання на колекцію, ініціалізовану цією ідіомою "подвійної дужки" (або якщо ми називаємо її справжнім іменем - анонімний клас із блоком ініціалізатора), ви неявно тримаєте посилання на зовнішній об'єкт, що може викликати неприємну пам'ять протікання. Я рекомендую взагалі уникати цього.
ddimitrov

51
"Подвійна дужка ініціалізація" - це дуже евфемічна назва створення анонімного внутрішнього класу, обмацування того, що відбувається насправді, і звучання так, ніби внутрішні класи призначені для використання таким чином. Це шаблон, який я вважаю за краще залишатися прихованим.
erickson

11
Майже, це насправді не статичний блок, а "блок ініціалізатора", який відрізняється тим, що він виконується в інший час (див. Посилання, яке я вклав у відповідь для більш детальної інформації)
Борис Терзич

279

Дисперсія параметрів спільного з'єднання в типі:

public class Baz<T extends Foo & Bar> {}

Наприклад, якщо ви хочете взяти параметр, який є "Порівняним" і "Колекція":

public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
   return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}

Цей надуманий метод повертає істину, якщо дві задані колекції рівні або якщо одна з них містить даний елемент, інакше помилковий. Слід зазначити, що на аргументах b1 і b2 можна викликати методи як Comprable, так і Collection.


Моє улюблене використання для цього - коли вам потрібен метод, який приймає придатну наслідку.
Ніл Коффі

5
Чи можливо там "АБО" замість &?
mainstringargs

9
@Grasper: Ні, АБО (нерозбірливий союз) не передбачено в цьому контексті. Але ви можете замість цього використовувати тип даних, що не з'єднуються, наприклад "A <B". Цей тип є подвійним типу типу Pair <A, B>. Подивіться на функціональну бібліотеку Java або основні бібліотеки Scala для прикладу такого типу даних.
Апокаліпс

5
Ви повинні сказати, що Ви ОБОВ'ЯЗКОВО розширюєте лише один клас та кілька інтерфейсів -> public class Baz <T розширює Clazz & Interface1 & InterfaceI ..., а не клас Baz <T розширює Clazz1 & ClazzI>
JohnJohnGa

220

Днями мене здивували ініціалізатори екземплярів. Я видаляв декілька методів, складених кодом, і в результаті створив кілька ініціалізаторів екземплярів:

public class App {
    public App(String name) { System.out.println(name + "'s constructor called"); }

    static { System.out.println("static initializer called"); }

    { System.out.println("instance initializer called"); }

    static { System.out.println("static initializer2 called"); }

    { System.out.println("instance initializer2 called"); }

    public static void main( String[] args ) {
        new App("one");
        new App("two");
  }
}

Виконання mainметоду покаже:

static initializer called
static initializer2 called
instance initializer called
instance initializer2 called
one's constructor called
instance initializer called
instance initializer2 called
two's constructor called

Я думаю, це було б корисно, якби у вас було кілька конструкторів і потрібен загальний код

Вони також забезпечують синтаксичний цукор для ініціалізації ваших занять:

List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};

Map<String,String> codes = new HashMap<String,String>(){{ 
  put("1","one"); 
  put("2","two");
}};

38
Перевага цього перед явним методом, який потрібно викликати, полягає в тому, що якщо хтось додає конструктор пізніше, їм не потрібно пам'ятати, щоб викликати init (); це буде зроблено автоматично. Це може запобігти помилкам майбутніх програмістів.
Містер Блискучий та Новий 安 宇

40
Крім того, на відміну від методу init (), він може ініціалізувати заключні поля.
Даррон

2
Що робити, якщо розширити заняття та інстанціювати різних дітей? Чи все одно буде поводитись так само?
Kezzer

12
Люди часто видають сертифікати (наприклад, stackoverflow.com/questions/281100/281127#281127 ) і особливо ставлять під сумнів їх технічні достоїнства. Але якби більше програмістів тут вивчали свої SCJP, це не вважало б багато прихованих особливостей. ;-)
Jonik

12
Я думаю, що навіть "java за 24 години" книга має цю "очевидну особливість". читайте ще хлопці
:)

201

JDK 1.6_07 + містить додаток під назвою VisualVM (bin / jvisualvm.exe), який є приємним графічним інтерфейсом, розташованим поверх багатьох інструментів. Це здається більш всеосяжним, ніж JConsole.


І він має плагін (це netbeans thingie), який дозволяє йому використовувати плагіни Jconsole. Доволі приємний.
Thorbjørn Ravn Andersen

VisualVM - найкраща річ з нарізаного хліба, насправді! Шкода, що він не має всіх функцій, коли працює проти JDK 1.5
sandos

Я вважаю VisualVM повільним або непридатним в деяких умовах. У комерційного YourKit немає цієї проблеми, але, на жаль, не є безкоштовним.
Roalt

Новітні версії Visual VM від JDK 1.6.0_22 та новіших версій значно вдосконалені. Я б сказав, що JDK1.7 має ще кращу версію.
djangofan


156

Для більшості людей, з якими я співбесідую для позицій розробника Java, позначені блоки дуже дивовижні. Ось приклад:

// code goes here

getmeout:{
    for (int i = 0; i < N; ++i) {
        for (int j = i; j < N; ++j) {
            for (int k = j; k < N; ++k) {
                //do something here
                break getmeout;
            }
        }
    }
}

Хто сказав, що gotoв Java - це лише ключове слово? :)


2
Ну, я б вважав за краще мати варіант зробити це декількома способами. Наприклад, я бачив людей, які використовують System.exit (1); у коді Servlet та EJB, але це не означає, що ми повинні видалити System.exit (); від JDK, правда?
Георгій Болюба

31
За певних обставин, всередині вкладеної конструкції циклу може бути корисним перейти до наступної ітерації зовнішньої петлі. Це було б розумно використовувати цю функцію.
alasdairg

75
Що особливо невідомо багатьом програмістам (і, мабуть, так само добре), це те, що ви можете насправді позначити і вирватися з будь-якого старого блоку. Це не повинно бути циклом - ви можете просто визначити якийсь довільний блок, дати йому мітку і використовувати перерву з ним.
Ніл Коффі

27
Це зовсім не гото, воно може повернутися лише до попередньої ітерації (тобто: ви не можете стрибати вперед). Це той самий механізм, який виникає, коли ітерація повертає помилку. Скажімо, що Java має goto - це як сказати будь-якою мовою, компілятор якої створює інструкцію JUMP, має оператор goto.
Зомбі

4
Отже, ви берете інтерв'ю на основі дрібниць Java, а не на здатності вирішувати проблеми та продумувати проекти. Я переконуюсь, що ніколи не беру інтерв’ю з вашою компанією. :)
Джавід Джамай

144

Як щодо коваріантних типів повернення, які існували з JDK 1.5? Це досить погано розрекламовано, оскільки це несексичне доповнення, але, як я розумію, це абсолютно необхідне для роботи дженериків.

По суті, компілятор тепер дозволяє підкласу звузити тип повернення переопределеного методу як підклас повернення вихідного методу. Отже, це дозволено:

class Souper {
    Collection<String> values() {
        ...
    }
}

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}

Ви можете зателефонувати за valuesметодом підкласу та отримати відсортований потік, безпечний Setвід Strings, без того, щоб придумувати його ConcurrentSkipListSet.


Чи можете ви надати приклад використання?
Аллайн Лалонде

24
Я цим дуже користуюся. clone () - чудовий приклад. Він повинен повернути Object, що означає, що вам доведеться сказати, наприклад, (List) list.clone (). Однак якщо ви оголосите як список клонів () {...}, то команда не потрібна.
Джейсон Коен

142

Передача контролю в остаточному блоці викидає будь-який виняток. Наступний код не кидає RuntimeException - він втрачається.

public static void doSomething() {
    try {
      //Normally you would have code that doesn't explicitly appear 
      //to throw exceptions so it would be harder to see the problem.
      throw new RuntimeException();
    } finally {
      return;
    }
  }

З http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


7
Це неприємно, але це також просто логічний наслідок того, як нарешті працює. Контроль потоку спробувати / зловити / нарешті виконує те, що призначено робити, але лише в певних межах. Так само ви повинні бути обережними, щоб не викликати виняток всередині блоку catch / нарешті, або ви також викинете початковий виняток. І якщо ви зробите System.exit () всередині блоку спробу, блок нарешті не буде викликаний. Якщо ви порушите нормальний потік, ви порушите нормальний потік ...
Ніл Коффі

Не використовуйте нарешті {return; } але лише нарешті {код без повернення}. Це логічно, оскільки, нарешті, також передбачається виконати, коли сталися винятки, і єдиним можливим значенням повернення як обробника винятків повинно бути ігнорування винятку і - справді - повернення.
екстранеон

21
Це виглядає як більше "gotcha", ніж прихована функція, хоча є способи її використання в якості одного, використання цього методу не було б гарною ідеєю.
davenpcj

Eclipse надсилає попередження, якщо це зробити. Я з Eclipse. Якщо ви хочете зловити виняток ... тоді зловіть виняток.
геліос

Ось за що ви платите за брудний код, який повертається з середини методу. Але все ж приємний приклад.
Ростислав Матл

141

Ніколи не бачив, щоб хтось згадував про те, що він був реалізований таким чином, що перевірка наявності null не потрібна.

Замість:

if( null != aObject && aObject instanceof String )
{
    ...
}

просто використовуйте:

if( aObject instanceof String )
{
    ...
}

9
Прикро, що це така маловідома особливість. Я бачив багато коду, схожого на перший блок коду.
Пітер Долберг

4
Це тому, що у Java є особливий (прихований) нульовий тип, який ви не бачите і не можете посилатися.
Нік Христов

Найгірше - перевірити наявність нуля перед тим, як freeing або deleteing у C / C ++. Така фундаментальна концепція.
Томас Едінг

134

Дозвіл методів та конструкторів у перерахунках мене здивував. Наприклад:

enum Cats {
  FELIX(2), SHEEBA(3), RUFUS(7);

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}

Ви навіть можете мати "постійне тіло конкретного класу", яке дозволяє певним значенням перерахування переосмислювати методи.

Більше документації тут .


20
Насправді дивовижна функція насправді - змушує OO і вирішує безліч проблем ініціалізації дуже чисто.
Білл К

5
Енум як одиночний? Енум лише з одним значенням?
Георгій Болюба

6
Георгій: Синглтон - це один екземпляр об'єкта, а не об'єкт з одним значенням.
дшав

20
@Georgy: див. Також пункт 3 у Ефективній Java Джошуа Блоха (2-е видання); "Хоча цей підхід ще не набув широкого поширення, одноелементний тип enum - найкращий спосіб реалізувати сингтон".
Джонік

3
Незначна нитка: mAgeповинна бути остаточною. Рідко буває причина для нестатевих полів у перерахунках.
Йоахім Зауер

121

Параметри типу для загальних методів можна точно вказати так:

Collections.<String,Integer>emptyMap()

10
І по богу це потворно і заплутано. І не має значення для безпеки типу.
Кріс Бродфут

8
Мені це подобається. Це робить ваш код трохи більш явним і як такий більш зрозумілим для бідної дернини, якій доведеться підтримувати його через рік-два.
екстранеон

6
Це насправді дуже корисно в ситуаціях, коли ви оголосили статичний загальний метод, такий як public static <T> T foo(T t). Потім ви можете телефонувати вClass.<Type>foo(t);
Фінбарр

Чомусь це, здається, не працює зі статично імпортованими методами. Цікаво, чому.
оксайт

Це особливо корисно при використанні потрійних ifs із поверненням. Наприклад return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList(). Він також корисний для викликів методу, де простий Collections.emptyMap () дасть помилку компіляції.
Андреас Холстенсон

112

Ви можете використовувати enums для реалізації інтерфейсу.

public interface Room {
   public Room north();
   public Room south();
   public Room east();
   public Room west();
}

public enum Rooms implements Room {
   FIRST {
      public Room north() {
         return SECOND;
      }
   },
   SECOND {
      public Room south() {
         return FIRST;
      }
   }

   public Room north() { return null; }
   public Room south() { return null; }
   public Room east() { return null; }
   public Room west() { return null; }
}

РЕДАКТ: Через роки….

Я використовую цю функцію тут

public enum AffinityStrategies implements AffinityStrategy {

https://github.com/peter-lawrey/Java-Thread-Affinity/blob/master/src/main/java/vanilla/java/affinity/AffinityStrategies.java

За допомогою інтерфейсу розробники можуть визначати власні стратегії. За допомогою enumзасобу я можу визначити вбудовану в них колекцію (з п'яти).


27
Це безумство. (+1)
Головоногі

12
@Arian це не божевілля. ЦЕЙ. Є. JAVAAAAAAHHHH!
slezica

1
WHAAAAAT ні, я з Адріаном. Це не Java. Це безумство. Я вмираю використовувати це.
slezica

104

Як і у Java 1.5, у Java зараз є набагато чистіший синтаксис для запису функцій змінної арту. Отже, замість того, щоб просто передавати масив, тепер ви можете зробити наступне

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}

бари автоматично перетворюється в масив зазначеного типу. Не величезна виграш, але все-таки виграш.


23
Важливим у цьому є те, що при виклику методу ви можете написати: foo ("перший", "другий", "третій")
Стів Армстронг

9
тому старий привіт світ можна переписати; public static void main (String ... args) {System.out.println ("Привіт, світ!"); }
Каруссел

@Karussell Можливо, але, здавалося б, аргументи не мають значення: p
Келлі Елтон

93

Мій улюблений: скинути всі сліди стека ниток для стандартного виходу.

windows: CTRL- Breakу вашому java cmd / console window

unix: kill -3 PID


15
Також ctrl- \ в Unix. Або використовувати jstack від JDK.
Том Хотін - тайклін

9
Дякую, ти щойно навчила мене, у мене на клавіатурі є Breakклавіша.
Емі Б

2
У вікнах CTRL-BREAK працює лише у тому випадку, якщо процес запущений у поточному вікні консолі. Ви можете використовувати JAVA_HOME / bin / jstack.exe замість цього. Просто надайте йому ідентифікатор процесу Windows.
Джавід Джамай

Я думав, що це вбивство
Нік Христов

@ Nick, так SIGQUIT - це сигнал №3.
Кріс Маццола

89

Кілька людей розмістили інформацію про ініціалізатори екземплярів, ось корисне для цього використання:

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};

Це швидкий спосіб ініціалізації карт, якщо ви просто робите щось швидке і просте.

Або використовуючи його для створення прототипу швидкого розгорнутого кадру:

JFrame frame = new JFrame();

JPanel panel = new JPanel(); 

panel.add( new JLabel("Hey there"){{ 
    setBackground(Color.black);
    setForeground( Color.white);
}});

panel.add( new JButton("Ok"){{
    addActionListener( new ActionListener(){
        public void actionPerformed( ActionEvent ae ){
            System.out.println("Button pushed");
        }
     });
 }});


 frame.add( panel );

Звичайно, цим можна зловживати:

    JFrame frame = new JFrame(){{
         add( new JPanel(){{
               add( new JLabel("Hey there"){{ 
                    setBackground(Color.black);
                    setForeground( Color.white);
                }});

                add( new JButton("Ok"){{
                    addActionListener( new ActionListener(){
                        public void actionPerformed( ActionEvent ae ){
                            System.out.println("Button pushed");
                        }
                     });
                 }});
        }});
    }};

Так чи інакше, начебто до Java додано ключове слово "з" (функціональність функціоналу). Це може бути дуже зручно, нещодавно я пробурчав, тому що init масивів не було доступно для Collections. Дякую!
PhiLho

15
Однак є один побічний ефект від використання цього. Створюються анонімні об’єкти, що може бути не завжди добре.
Аміт

17
Хоча, дивлячись на це більше, я мушу сказати, що мене дивно приваблює природне гніздування, яке це забезпечує, навіть версія "Зловживання".
Білл К

4
Так - мені дуже подобається "зловживана" версія, я думаю, це дійсно дуже зрозуміло і читабельно, але, мабуть, це лише я.
затримано

3
Абсолютно згоден, ієрархія коду, що відображає ієрархію gui, - це величезне вдосконалення щодо послідовності викликів методів.
opsb

88

Динамічні проксі-сервери (додані в 1.3) дозволяють визначити новий тип під час виконання, який відповідає інтерфейсу. Це було корисно дивно кілька разів.


10
Динамічні проксі - це прекрасна причина вибрати інтерфейс Foo і використовувати його скрізь, з класом "FooImpl" за замовчуванням. Спочатку це може здатися негарним ("Чому б просто не мати клас під назвою Foo?"), Але переваги з точки зору майбутньої гнучкості та макетності для одиничних тестів є корисними. Хоча є способи зробити це і для неінтерфейсів, вони зазвичай вимагають додаткових матеріалів, таких як cblib.
Дарієн

82

остаточну ініціалізацію можна відкласти.

Це гарантує, що навіть при складному потоці логіки повертаються завжди значення. Пропустити справу і повернути нуль випадково занадто просто. Це не робить повернення нуля неможливим, просто очевидно, що це спеціально:

public Object getElementAt(int index) {
    final Object element;
    if (index == 0) {
         element = "Result 1";
    } else if (index == 1) {
         element = "Result 2";
    } else {
         element = "Result 3";
    }
    return element;
}

Це дивно. Чи можна сказати справедливо: "Значення кінцевої змінної можна встановити один раз", незалежно від того, де відбувається набір?
David Koelle

29
Так, але ще сильніше: "Значення кінцевої змінної потрібно встановити один раз"
Аллайн Лалонд

6
+1 Погодьтеся, це ще один цінний інструмент для виявлення помилок під час компіляції, і той, який програмісти чомусь сором’язливий використовувати. Зауважте, що оскільки від Java 5 далі "final" також має наслідки для безпеки потоку, можливість встановити остаточну змінну під час конструктора неоціненна.
Ніл Коффі

4
Хоча для цього конкретного методу я б просто використовував кілька повернень. Насправді, у більшості випадків, коли це застосовно, я, ймовірно, перероблюю його в окремий метод і використовую кілька повернень.
ripper234

Мені це подобається! Я видаляв остаточне ключове слово завжди, бо вважав, що воно не вдасться. Дякую!
KARASZI István

62

Я думаю, що ще одна "недооцінена" особливість Java - це сам JVM. Це, мабуть, найкращий доступний VM. І він підтримує безліч цікавих і корисних мов (Jython, JRuby, Scala, Groovy). Усі ці мови можуть легко та безперешкодно співпрацювати.

Якщо ви розробляєте нову мову (як, наприклад, у шкалі шкали), у вас одразу є доступні всі наявні бібліотеки, тому ваша мова є «корисною» з самого початку.

Усі ці мови використовують оптимізацію HotSpot. VM дуже добре контролює та налагоджує.


18
Ні. Це насправді не дуже хороший ВМ. Він був розроблений виключно для управління JAVA. Незрядні динамічні та функціональні мови з цим не працюють добре. З вас хочеться використовувати VM, ви повинні використовувати .NET / Mono. Це було розроблено для роботи з
КОЖНОЮ

14
Насправді JVM призначений виключно для запуску Java-Bytecodes. Ви можете скласти найсучасніші мови до Java Bytecode. Єдине, чого не вистачає Java Bytecode - це динамічна підтримка мови, покажчики та підтримка рекурсії хвоста.
mcjabberz

12
@ Hades32: насправді .NET VM досить схожий на JVM. Підтримка динамічних мов отримала лише відносно недавно (з DLR), і підтримка Java 7 збирається отримати таку підтримку. І класична "КОЖНА мова" .NET (C #, Visual Basic.NET, ...) має майже однаковий набір функцій.
Йоахім Зауер

13
JVM не підтримує дженерики, тоді як .NET VM. JVM ніде не кращий.
Сліпий

3
Не знижуйте скарги на конкретні мовні особливості, які безпосередньо не підтримуються JVM ... але я схильний вважати стабільність, узгодженість між платформами та хорошу ефективність - це набагато вище причин, через які JVM отримує додаткові бали. Я працюю з Java на сервері вже багато років на багатьох платформах (включаючи AS / 400) і мені вдалося майже забути про це повністю - помилки майже завжди в коді, який я можу виправити, і це просто не збивається.
Роб Уілан

58

Ви можете визначити анонімний підклас і безпосередньо викликати метод на ньому, навіть якщо він не реалізує інтерфейсів.

new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");

@Vuntic - Це дозволяє вам визначити простий клас у контексті, який він потрібен.
ChaosPandion

1
@Chaos, але чому? Отриманий фактичний приклад, де це корисно?
Thorbjørn Ravn Andersen

10
@Wouter - У такому випадку метод, який викликається на анонімному об'єкті ( start()), фактично не визначений у підкласі ...
Axel

Насправді це дуже корисна функція, якщо ви розширюєте базовий клас, який виконує необхідні настройки, викликає метод, який ви пишете, а потім відриває. Відкиньте річ, зателефонувавши до методу в базовому класі (якому я, мабуть, не назвав би те саме ім’я). Там приклад використання (не визначення) тут
AmigoNico

56

AsList метод java.util.Arraysдозволяє гарне поєднання, загальних списків параметрів методів і Autoboxing:

List<Integer> ints = Arrays.asList(1,2,3);

15
ви хочете обернути повернутий список конструктором List, інакше вкладиші будуть фіксованого розміру (оскільки він підтримується масивом)
KitsuneYMG

2
Arrays.asListМає незвичайну особливість , що ви можете set()елементи , але не add()або remove(). Тому я зазвичай загортаю його в new ArrayList(...)або в Collections.unmodifiableList(...), залежно від того, хочу я, щоб список мінявся чи ні.
Крістіан Семрау

53

Використання цього ключового слова для доступу до полів / методів, що містять клас із внутрішнього класу. Нижче, досить надуманий приклад, ми хочемо використовувати поле sortAscending контейнера класу з анонімного внутрішнього класу. Використання ContainerClass.this.sortAscending замість цього.sortAscending робить трюк.

import java.util.Comparator;

public class ContainerClass {
boolean sortAscending;
public Comparator createComparator(final boolean sortAscending){
    Comparator comparator = new Comparator<Integer>() {

        public int compare(Integer o1, Integer o2) {
            if (sortAscending || ContainerClass.this.sortAscending) {
                return o1 - o2;
            } else {
                return o2 - o1;
            }
        }

    };
    return comparator;
}
}

4
Це потрібно лише в тому випадку, якщо ви затінили ім'я (у вашому випадку - ім'я параметра параметра). Якщо ви назвали аргумент чимось іншим, ви можете безпосередньо отримати доступ до змінної sortAscending члена класу Container, не використовуючи "this".
ск.

7
Ще корисно мати посилання на клас, що додається, наприклад. якщо вам потрібно передати його якомусь методу чи конструктору.
PhiLho

Часто використовується в розробці верстки Android, щоб отримати контекст від, скажімо, слухача кнопки, з MyActivity.this.
espinchi

52

Насправді не особливість, але забавна хитрість, яку я нещодавно виявив на якійсь веб-сторінці:

class Example
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
    http://Phi.Lho.free.fr

    System.exit(0);
  }
}

є дійсною програмою Java (хоча вона генерує попередження). Якщо ви не бачите чому, дивіться відповідь Григорія! ;-) Ну, підкреслення синтаксису тут також дає підказку!


15
акуратний, ярлик з коментарем :)
Thorbjørn Ravn Andersen

46

Це не зовсім "приховані функції" і не дуже корисні, але можуть бути надзвичайно цікавими в деяких випадках:
Клас sun.misc.Unsafe - дозволить вам реалізувати пряме управління пам’яттю на Java (ви навіть можете писати самомодифікуючий код Java за допомогою це якщо ви багато намагаєтесь):

public class UnsafeUtil {

    public static Unsafe unsafe;
    private static long fieldOffset;
    private static UnsafeUtil instance = new UnsafeUtil();

    private Object obj;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);

            unsafe = (Unsafe)f.get(null);
            fieldOffset = unsafe.objectFieldOffset(UnsafeUtil.class.getDeclaredField("obj"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

20
це сонце. * API, який насправді не є частиною мови Java
DW.

Існує ряд інших цікавих методів щодо небезпечних, таких як створення об'єкта без виклику конструктора, методів malloc / realloc / free style.
Пітер Лоурі

Я особливо люблю примітивні геттери та сетери на місцях пам'яті, як putDouble (довга адреса, подвійний d).
Даніель

42

Під час роботи в Swing мені подобається прихована Ctrl- Shift- F1функція.

Він скидає компонентне дерево поточного вікна.
(Припустимо, що ви не пов’язали цей натискання клавіші з чимось іншим.)


1
Швидше за все, у вашого менеджера вікон щось пов'язане з цим ключем. Gnome не пов'язує його, тому я припускаю, що ви використовуєте KDE, який прив'язує його до "переходу на робочий стіл 13". Ви можете змінити його, перейшовши на Панель управління, Регіональні, Клавіші швидкого доступу та видаливши відображення для Shift-Ctrl-F1
Devon_C_Miller

40

Кожен файл класу починається зі шістнадцяткового значення 0xCAFEBABE, щоб ідентифікувати його як дійсний байт-код JVM.

( Пояснення )


38

Я голосую за java.util.concurrent зі своїми одночасними колекціями та гнучкими виконавцями, які дозволяють серед інших пулів потоків, запланованих завдань та узгоджених завдань. DelayQueue - мій особистий фаворит, де елементи стають доступними після зазначеної затримки.

java.util.Timer і TimerTask можуть спокійно перепочити.

Також не точно приховано, але в іншому пакеті, ніж інші класи, пов’язані з датою та часом. java.util.concurrent.TimeUnit корисний при перетворенні між наносекундами, мікросекундами, мілісекундами та секундами.

Він читає набагато краще, ніж звичайний деякийValue * 1000 або деякийValue / 1000.


Нещодавно відкритий CountDownLatchі CyclicBarrier- такий корисний!
Рафаель

37

Ключове слово затвердження на рівні мови .


19
Проблема зі ствердженням полягає в тому, що її потрібно включати під час виконання.
екстранеон

10
Але якщо він відключений - це ніби його немає. Ви можете додати в свій код стільки тверджень, скільки хочете, і ви не будете штрафувати за ефективність, якщо вони відключені.
Раві Валлау

5
Я вважаю, що це гарна річ у твердженні: її можна вимкнути без штрафу.
andref

проблема полягає в тому, що якщо ви випадково реалізували побічний ефект у ствердженні, вам доведеться ввімкнути твердження про те, що програма ур працює,
Chii

Щоб визначити, чи утвердження включені, ви можете використовувати {boolean assertsOn = false; assert assertsOn = вірно; якщо (assertsOn) {/ * комплексна перевірка * /}}. Це також дозволяє увімкнути або викинути виняток, якщо стан затвердження не очікується.
fernacolo

37

Насправді не є частиною мови Java, але розбірник javap, який поставляється з JDK Sun, широко не відомий і не використовується.


36

Додавання конструкції для кожного циклу в 1.5. Я <3 це.

// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
  System.out.println(foo.toString());
}

І може використовуватися в вкладених екземплярах:

for (Suit suit : suits)
  for (Rank rank : ranks)
    sortedDeck.add(new Card(suit, rank));

Конструкція for для кожного також застосовна для масивів, де вона приховує змінну індексу, а не ітератор. Наступний метод повертає суму значень у масиві int:

// Returns the sum of the elements of a
int sum(int[] a) {
  int result = 0;
  for (int i : a)
    result += i;
  return result;
}

Посилання на документацію Sun


30
Я думаю, що використання iтут є надзвичайно заплутаним, оскільки більшість людей очікують, що я буду індексом, а не елементом масиву.
cdmckay

Отже ... int sum (масив int []) {int result = 0; для (елемент int: масив) {результат + = елемент; } повернути результат; }
Дрю

28
Єдине, що мене змушує з цього приводу, це те, що здається, було б створити ключове слово для доступу до значення кількості циклу, але ви не можете. Якщо я хочу перетворити цикл на два масиви та внести зміни до другого на основі значень у першому, я змушений використовувати старий синтаксис, оскільки у мене немає зміщення у другому масиві.
Jherico

6
Прикро, що він також не працює з перерахунками, як ті, що використовуються в JNDI. Це назад до ітераторів.
екстранеон

3
@extraneon: подивіться на Collections.list (Перерахування <T> e). Це повинно допомогти в ітераційному перерахуванні в циклі foreach.
Вернер Леманн

34

я особисто виявив java.lang.Voidдуже пізно - покращує читабельність коду в поєднанні з загальними характеристиками, наприкладCallable<Void>


2
не зовсім. в якийсь момент вам потрібно бути конкретним: Executors.newSingleThreadExecutor (). submit (новий Callable <Void> () {..}) - ви не можете створити інстанціювання нового Callable <?> (), вам потрібно вказати явний тип - таким чином, це альтернатива Calloble <Object>.
Рахель Люті

4
Пустота є більш специфічною, ніж Об'єкт, оскільки недійсна може бути лише нульовою, Об'єкт може бути будь-чим.
Пітер Лорі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.