2. Double.compare method returns a negative if the first argument is less than the second argument, 0 if they are equal, and a positive value otherwise.
3. If you know that the IDs are not negative or that their absolute value is at most (Integer.MAX_VALUE - 1) / 2, you are safe to use integer substraction in the compareTo method. Of course, the subtraction trick doesn’t work for floating-point numbers. Subtraction of two floating-point numbers can round to 0 if they are close enough.
4. If you flip the parameters of compareTo, the sign (but not necessarily the actual value) of the result must also flip. This implies that x.compareTo(y) must throw an exception if y.compareTo(x) throws an exception. The documentation of the Comparable interface suggests that the compareTo method should be compatible with the equals method. That is, x.compareTo(y) should be zero exactly when x.equals(y).
5. If subclasses have different notions of comparison, then you should outlaw comparison of objects that belong to different classes. Each compareTo method should start out with the test:
if (getClass() != other.getClass()) throw new ClassCastException();
If there is a common algorithm for comparing subclass objects, simply provide a single compareTo method in the superclass and declare it as final.
6. You can use instanceof to check whether an object implements an interface.
7. Each class can have only one superclass but implement multiple interfaces.
8. The clone method is a protected method of Object, which means that your code cannot simply call it. The rules for protected access make sure that a subclass can call a protected clone method only to clone its own objects.
9. Think about the way in which the Object class can implement clone. It knows nothing about the object at all, so it can make only a field-by-field copy. If all data fields in the object are numbers or other basic types, copying the fields is just fine. But if the object contains references to subobjects, then copying the field gives you another reference to the same subobject, so the original and the cloned objects still share some information. The default cloning operation is “shallow”.—it doesn’t clone objects that are referenced inside other objects.
10. If subobjects are mutable, and you must redefine the clone method to make a deep copy that clones the subobjects as well. A class must implement the Cloneable interface and redefine the clone method to call super.clone() and assign it the public access modifier to allow objects to be cloned by any method.
11. The Cloneable interface has no method and merely serves as a tag, indicating that the class designer understands the cloning process. Objects are so paranoid about cloning that they generate a checked exception (CloneNotSupportedException) if an object requests cloning but does not implement that interface.
12. There is no problem not to override the clone method in the subclass if superclass provides the implementation of clone if the fields of subclass are all primitive types.
13. All array types have a clone method that is public, not protected. You can use it to make a new array that contains copies of all elements (elements are not deeply copied).
14. A common pattern in programming is the callback pattern. In this pattern, you want to specify the action that should occur whenever a particular event happens. Consider using an interface in Java for callback function.
15. There are three reasons for inner classes:
a) Inner class methods can access the data from the scope in which they are defined—including the data that would otherwise be private.
b) Inner classes can be hidden from other classes in the same package.
c) Anonymous inner classes are handy when you want to define callbacks without writing a lot of code.
16. An object that comes from an inner class has an implicit reference to the outer class object that instantiated it. Through this pointer, it gains access to the total state of the outer object. static inner classes do not have this added pointer.
17. A method could refer to the data fields of the object invoking the method. An inner class method gets to access both its own data fields and those of the outer object creating it. For this to work, an object of an inner class always gets an implicit reference to the object that created it.
18. The outer class reference is set in the constructor. The compiler modifies all inner class constructors, adding a parameter for the outer class reference.
19. Only inner classes can be private. Regular classes always have either package or public visibility. Any static fields declared in an non-static inner class must be final and a compile-time constant. A non-static inner class cannot have static methods or initializers.
20. The proper syntax for the outer reference is OuterClass.this.
21. You can invoke the inner object constructor more explicitly using:
outerObject.new InnerClass(construction parameters)
22. You refer to an inner class as OuterClass.InnerClass when it occurs outside the scope of the outer class.
23. Inner classes are a phenomenon of the compiler, not the virtual machine. Inner classes are translated into regular class files with $ (dollar signs) delimiting outer and inner class names, and the virtual machine does not have any special knowledge about them.
24. When you run javap -private OuterClass$InnerClass, you can see the compiler has generated an additional final instance field, this$0, for the reference to the outer class. You can also see the OuterClass parameter for the constructor.
25. Inner classes are genuinely more powerful than regular classes because they have more access privileges. When you run javap -package OuterClass, you can see the compiler has generated a package access static method (with name like access$0 and accept outer class instance as parameter) to access the private field of outer class if inner class contains codes to visit it. And the compiler has replaced the access to the outer class field in inner class with that generated method.
26. If an inner class accesses a private data field, then it is possible to access that data field through other classes added to the package of the outer class, but to do so requires skill and determination. A programmer cannot accidentally obtain access but must intentionally build or modify a class file for that purpose.
27. For private inner class, there are no private classes in the virtual machine, so the compiler produces the next best thing: a package-visible class with a private constructor:
private OuterClass$InnerClass(OuterClass)
And there is a second package-visible constructor ( for
OuterClass$InnerClass (OuterClass, OuterClass$1)
And the compiler translates the call of outerObj.new InnerClass() to new OuterClass$InnerClass(outerObj, null)
28. You can define the class locally in a single method. Local classes are never declared with an access specifier (public or private). Their scope is always restricted to the block in which they are declared.
29. Local inner classes can not only access the fields of their outer classes but also even access local variables. However, those local variables must be effectively final. That means, they may never change once they have been assigned. Before Java SE 8 they must be declared as final.
30. The local inner class must have copied the local variable of its declaring method as an instance field, before the local variable value went away when the method exits. The compiler synthesizes the name OuterClass$1InnerClass for the local inner class. The compiler detects access of local variables, makes matching instance fields for each one of them, and copies the local variables into the constructor so that the instance fields can be initialized. When you use javap to peek at the local inner class, you can see the compiler has generated an additional final field (with name like var$LocalVariableName) to store the local variable it accesses and added one more parameter to the constructor to pass in the local variable value. The value of the local variable will be passed to the local inner class constructor when it's instantiated. Since the methods of a local class can refer only to local variables that are effectively final, it is guaranteed that the local variable and the copy made inside the local class will always have the same value.
31. You don’t have to initialize a final variable when you define it. A final variable that isn’t initialized when it is defined is often called a blank final variable.
32. If you do want to change the local variable in the local inner class, you can use an array of length 1. The array variable is still effectively final, but that merely means that you can’t have it refer to a different array. You are free to mutate the array elements.
33. If you want to make only a single object of a local inner class, you don’t even need to give the class a name. Such a class is called an anonymous inner class. The syntax is:
new SuperType(construction parameters) { inner class methods and data }
Here, SuperType can be an interface (the inner class implements it ) or a class ( the inner class extends it ).
34. The anonymous inner class doesn’t have a name thus it cannot have a constructor, Instead, the construction parameters are given to the superclass constructor. You can initialize it via instance initializer block.
35. To instantiate and initialize an anonymous ArrayList :
new ArrayList<String>() {{ add("Harry"); add("Tony"); }}
36. getClass() fails in a static method, Use the following expression instead:
new Object(){}.getClass().getEnclosingClass()
Here, new Object(){} makes an object of an anonymous subclass of Object, and getEnclosingClass gets its enclosing class—that is, the class containing the static method.
37. If you want to use an inner class simply to hide one class inside another—but you don’t need the inner class to have a reference to the outer class object. You can suppress the generation of that reference by declaring the inner class static. A static inner class is exactly like any other inner class, except that an object of a static inner class does not have a reference to the outer class object that generated it.
38. Inner classes that are declared inside an interface are automatically static and public.
39. You can use a proxy to create, at runtime, new classes that implement a given set of interfaces. Proxies are only necessary when you don’t yet know at compile time which interfaces you need to implement. To construct an instance of an actual class, you can simply use the newInstance method or use reflection to find a constructor. But you can’t instantiate an interface. You need to define a new class in a running program. To overcome this problem, some programs generate code, place it into a file, invoke the compiler, and then load the resulting class file. Naturally, this is slow, and it also requires deployment of the compiler together with the program.
40. The proxy class can create brand-new classes at runtime. Such a proxy class implements the interfaces that you specify. In particular, the proxy class has the following methods:
a) All methods required by the specified interfaces
b) All methods defined in the Object class
41. An invocation handler is an object of any class that implements the InvocationHandler interface. That interface has a single method:
Object invoke(Object proxy, Method method, Object[] args);
Whenever a method is called on the proxy object, the invoke method of the invocation handler gets called, with the Method object and parameters of the original call. The invocation handler must then figure out how to handle the call.
42. To create a proxy object, use the newProxyInstance method of the Proxy class. The method has three parameters:
a) A class loader. As part of the Java security model, different class loaders can be used for system classes, classes that are downloaded from the Internet, and so on. We can specify null to use the default class loader.
b) An array of Class objects, one for each interface to be implemented.
c) An invocation handler.
43. Proxies can be used for many purposes, such as
a) Routing method calls to remote servers
b) Associating user interface events with actions in a running program
c) Tracing method calls for debugging purposes
44. The proxy objects belong to a class that is defined at runtime. It has a name such as $Proxy0.
45. All proxy classes extend the class Proxy. A proxy class has only one instance field—the invocation handler, which is defined in the Proxy superclass. Any additional data required to carry out the proxy objects’ tasks must be stored in the invocation handler. All proxy classes override the toString, equals, and hashCode methods of the Object class and these methods simply call invoke on the invocation handler.
46. There is only one proxy class for a particular class loader and ordered set of interfaces. That is, if you call the newProxyInstance method twice with the same class loader and interface array, you get two objects of the same class. You can also obtain that class with the getProxyClass method of the Proxy class.
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
47. A proxy class is always public and final. If all interfaces that the proxy class implements are public, the proxy class does not belong to any particular package. Otherwise, all non-public interfaces must belong to the same package, and the proxy class will also belong to that package.
48. You can test whether a particular Class object represents a proxy class by calling the isProxyClass method of the Proxy class..
49. The rules for resolving method conflicts in multiple inheritances are :
- Superclasses win. If a superclass provides a concrete method, default methods with the same name and parameter types are simply ignored.
- Interfaces clash. If a superinterface provides a default method, and another interface supplies a method with the same name and parameter types (default or not), then you must resolve the conflict by overriding that method.
50. Use SuperInterface.super.method() to call default method in super interface. super is always referencing super class ( to be backward compatible).
51. You can never make a default method that redefines one of the methods in the Object class.
52. A lambda expression is a block of code that you can pass around so it can be executed later, once or multiple times.
53. The form of lambda expressions in Java is : parameters, the -> arrow, and an expression. If the code carries out a computation that doesn’t fit in a single expression, enclose it in {} with explicit return statements. If the parameter types of a lambda expression can be inferred, you can omit them. If a method has a single parameter with inferred type, you can even omit the parentheses. You never specify the result type of a lambda expression. It is always inferred from context.
54. It is illegal for a lambda expression to return a value in some branches but not in others.
55. You can supply a lambda expression whenever an object of an interface with a single abstract method is expected. Such an interface is called a functional interface.
56. It has always been possible for an interface to redeclare methods from the Object class such as toString or clone, and these declarations do not make the methods abstract.
57. The Java designers decided to stick with the familiar concept of interfaces instead of adding function types to the language. Conversion to a functional interface is the only thing that you can do with a lambda expression in Java. You can’t even assign a lambda expression to a variable of type Object—Object is not a functional interface.
58. The ArrayList class has a removeIf method whose parameter is a Predicate.
59. The expression System.out::println is a method reference that is equivalent to the lambda expression x -> System.out.println(x).
60. The :: operator in method reference separates the method name from the name of an object or class. There are three principal cases:
- object::instanceMethod
- Class::staticMethod
- Class::instanceMethod
In the first two cases, the method reference is equivalent to a lambda expression that supplies the parameters of the method. In the third case, the first parameter becomes the target of the method.
When there are multiple overloaded methods with the same name, the compiler will try to find from the context which one you mean. Just like lambda expressions, method references don’t live in isolation. They are always turned into instances of functional interfaces.
61. You can capture the this parameter in a method reference.(this::equals) It is also valid to use super. The method reference super::instanceMethod uses this as the target and invokes the superclass version of the given method.
62. Constructor references are just like method references, except that the name of the method is new.
63. You can form constructor references with array types : int[]::new is a constructor reference with one parameter: the length of the array. Array constructor references are useful to overcome a limitation of Java. It is not possible to construct an array of a generic type T. The expression new T[n] is an error since it would be erased to new Object[n].
64. A lambda expression has three ingredients:
- A block of code
- Parameters
- Values for the free variables, that is, the variables that are not parameters and not defined inside the code
The data structure representing the lambda expression must store the values for the free variables, We say that such values have been captured by the lambda expression.
65. The technical term for a block of code together with the values of the free variables is a closure.
66. In a lambda expression, you can only reference variables whose value doesn’t change (either inside the lambda or outside the lambda). The rule is that any captured variable in a lambda expression must be effectively final. An effectively final variable is a variable that is never assigned a new value after it has been initialized.
67. The body of a lambda expression has the same scope as a nested block. The same rules for name conflicts and shadowing apply. It is illegal to declare a parameter or a local variable in the lambda that has the same name as a local variable outside the lambda.
68. The point of using lambdas is deferred execution.
69. The following table lists the most important functional interfaces that are provided in the Java API:
70. Below table lists the 34 available specializations for primitive types int, long, and double. It is a good idea to use these specializations to reduce autoboxing :
71. Most of the standard functional interfaces have non-abstract methods for producing or combining functions. Predicate.isEqual(a) is the same as a::equals, but it also works if a is null. There are default methods and, or, negate for combining predicates.
72. If you design your own interface with a single abstract method, you can tag it with the @FunctionalInterface annotation. This has two advantages. The compiler gives an error message if you accidentally add another non-abstract method. And the javadoc page includes a statement that your interface is a functional interface.
73. The Comparator interface has a number of convenient static methods for creating comparators. The static comparing method takes a “key extractor” function that maps a type T to a comparable type (such as String). The function is applied to the objects to be compared, and the comparison is then made on the returned keys. You can chain comparators with the thenComparing method for breaking ties. You can specify a comparator to be used for the keys that the comparing and thenComparing methods extract:
Arrays.sort(people, Comparator.comparing(Person::getName,
(s, t) -> Integer.compare(s.length(), t.length())));
both the comparing and thenComparing methods have variants that avoid boxing of int, long, or double values.
74. The static nullsFirst and nullsLast methods take an existing comparator and modify it so that it doesn’t throw an exception when encountering null values but ranks them as smaller or larger than regular values :
Arrays.sort(people, comparing(Person::getMiddleName, nullsFirst(naturalOrder())));
75. The naturalOrder method makes a comparator for any class implementing Comparable. The static reverseOrder method gives the reverse of the natural order. To reverse any comparator, use the reversed instance method.
.