In preparation for the interview, I decided to refresh my memory and in general to look for the tricky and little-known nuances of the Java language. I offer you a selection of the five most interesting moments in my opinion.
The second part of the article has already arrived.
1. Non-static initialization blocks.')
Everyone, I think, knows that in Java there are static initialization blocks (
class initializers ) whose code is executed when the class is first loaded.
class Foo { static List<Character> abc; static { abc = new LinkedList<Character>(); for (char c = 'A'; c <= 'Z'; ++c) { abc.add( c ); } } }
But there are also non-static initialization blocks (
instance initializers ). They allow you to initialize objects regardless of which constructor was called or, for example, to log:
class Bar { { System.out.println("Bar: "); } }
This initialization method is very useful for anonymous inner classes that constructors cannot have. In addition, contrary to the limitation of Java syntax, using them, we can elegantly initialize the collection:
Map<String, String> map = new HashMap<String, String>() {{ put("", ""); put("", ""); put("", ""); }};
Very powerful tool, is not it?
JFrame frame = new JFrame() {{ add(new JPanel() {{ add(new JLabel("?") {{ setBackground(Color.BLACK); setForeground(Color.WHITE); }}); add(new JButton("!") {{ addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System.out.println(" - !"); } }); }}); }}); }};
The remaining four points are under the cut.
2. Nested classes in interfaces.The nested class in the interface is public (
public ) and static (
static ) even without explicitly specifying these modifiers. Placing a class inside an interface, we show that it is an integral part of the API of this interface and is not used anywhere else.
interface Colorable { public Color getColor(); public static class Color { private int red, green, blue; Color(int red, int green, int blue) { this.red = red; this.green = green; this.blue = blue; } int getRed() { return red; } int getGreen() { return green; } int getBlue() { return blue; } } } class Triangle implements Colorable { private Color color;
Since such a class is static, we can create an instance of it, not referring to the object of the enclosing class, but only indicating the type of the external interface or the class that implements it.
Colorable.Color color = new Colorable.Color(0, 0, 0); color = new Triangle.Color(255, 255, 255);
The most probably famous example of this idiom is the Map.Entry <K, V> class, which contains key-value pairs of an associative dictionary.
3. Covariants of returned types.Starting with Java SE 5, return types from covariant methods are covariant. This means that we can use the result subtype of the overlapped method as the result type in the overlapped method (
overriden ).
class Covariance implements Cloneable { @Override public Covariance clone() { Object cloned = null; try { cloned = super.clone(); } catch (CloneNotSupportedException exc) {
The Object.clone () method has the following signature:
protected Object clone()
Note that the return type is changed from Object to Covariance. Now, for example, there is no need to cast the output of the clone () method to a real object type, as was required in earlier versions of the JDK. Instead of this code:
Covariance foo = new Covariance(); Covariance bar = (Covariance)foo.clone();
We can safely write the following code:
Covariance foo = new Covariance(); Covariance bar = foo.clone();
4. Exit from any block of statements.Although
goto is a reserved Java keyword, you cannot use it in your programs. Until? It was replaced by the operators
break and
continue , allowing to interrupt and continue (respectively) not only the current cycle, but also any framing cycle, indicated by the label:
String a = "quadratic", b = "complexity"; boolean hasSame = false; outer: for (int i = 0; i < a.length(); ++i) { for (int j = 0; j < b.length(); ++j) { if (a.charAt(i) == b.charAt(j)) { hasSame = true; break outer; } } } System.out.println(hasSame);
But many do not even realize that in Java we can still not only interrupt the cycle using the
break statement, but also leave absolutely any block of statements. What is not a
goto statement , however, one-sided? As they say, forward and not a step back.
long factorial(int n) { long result = 1; scope: { if (n == 0) { break scope; } result = n * factorial(n - 1); } return result; }
The practical value of such jumps is highly questionable and violates the principles of structured programming, but I think it’s worth knowing about such a possibility.
5. Modification of data from internal classes.Although Java has the
final keyword, it is actually impossible to set the immutability of the object itself, and not the reference pointing to it (does not apply to primitives). Well, in principle, you can design an immutable class, providing only getters and pure functions, but you cannot, for example, create an immutable array. This, I think, is a significant omission in the design of the language. The reserved but forbidden keyword
const would be useful here. Looking forward to the next versions?
final int[] array = {1, 2, 3, 4, 5}; new Object() { void twice() { for (int i = 0; i < array.length; ++i) { array[i] *= 2; } } }.twice();
Thus, we can modirovat albeit finalized, but actually variable data, be it arrays or other non-persistent objects, even from the context of inner (
inner ) classes. With strings and shells of primitive types, unfortunately, this trick will not work. Don't let your
final keyword be misleading.
If you liked the article - to be continued ...