Java Core Technology Volume Ⅰ - Chapter 6 Interfaces, lambda expressions and inner classes

focus

1. Interface

2.lambda expression

3. Inner class

1. Interface

  • Interfaces are used to describe what classes should do, not to specify how they should be done

  • Properties of the interface:

    • An interface is not a class (i.e. an interface cannot be instantiated using new)
    • You can use instanceof to check whether an object implements an interface
    • You can use extends to extend the interface
    • Interfaces cannot contain instance fields, but can contain constants
    • The methods in the interface are automatically public, and the fields in the interface are public static final
    • Each class can have only one superclass, but can implement multiple interfaces
  • Interfaces can provide most of the benefits of multiple inheritance without the complexity and inefficiency of multiple inheritance

  • Java8 allows static methods to be added to interfaces; Java9 allows methods to be private methods, and the method can be either a static method or an instance method:

interface A{
    public static void test(){
        System.out.println("ooo");
    }    
}
interface B{
    private int test1(){
        return 1;
    }
    private static int test2(){
        return 2;
    }
}
  • You can provide a default implementation for any interface method, but it must be modified with default, but it will cause conflicts:

    • If a class implements two interfaces, and both interfaces provide default implementations of the same method, the compiler will report an error:
    class C implements A, B {}  // compiler error
    interface A{
        default void test(){
            System.out.println("interfaceA");
        }
    }
    interface B{
        default void test(){
            System.out.println("interfaceB");
        }
    }
    
    • If a class inherits a superclass and implements an interface, both the superclass and the interface have the same method, and the interface also provides a default implementation of the method, then class priority will eventually be taken (that is, only the superclass method is considered, and the methods in the interface The default method is ignored, which is also for compatibility with Java7):
    class C extends A implements B {}  // Create an instance c of class C, if you execute c.test() print "super class"
    class A{
        public void test(){
            System.out.println("super class");
        }
    }
    interface B{
        default void test(){
            System.out.println("interface");
        }
    }
    
  • The clone method of Object is a shallow copy by default (that is, the object referenced by the property in the object will only copy the reference address, and will not reallocate the memory of the referenced object). The problem with shallow copy is that it may change the properties in the original object (because it points to the same object), but it also needs to distinguish the situation:

    • The sub-object shared by the original object and the shallow clone object is an immutable object (such as an object of String type). This kind of sharing is safe. For example, there is a name attribute of String type in the Employee class. At this time, the original object is emp, and the clone object is emp2, emp2 will recreate a String type object after modifying the value of the name attribute, which means that the value of this attribute in the original object will not be changed

    • The sub-object shared by the original object and the shallow clone object is a variable object (such as a Date type object), and this kind of sharing is not safe

  • All array types will have a public clone method instead of defining protected. After calling, a copy of all elements of the original array will be created:

int[] a = {1, 2, 3};
int[] b = a.clone();
b[1] = 22;
System.out.println(a[1]);  // still 2

2.lambda expression

The expression is a passable block of code that can be executed one or more times in the future

  • Syntax rules for lambda expressions:

    • Empty parentheses need to be provided even if the expression has no parameters:
    ()->{
        for(int i = 0; i < 10; i++){
        	System.out.println(i);
        }
    }}
    
    • If the parameter types of an expression can be deduced, their types can be ignored:
    // No need to write as String first and String second
    Comparator<String> cmp = (first, second) -> first.length() - second.length()
    
    • If there is only one parameter in the method, and the parameter type can be deduced, the parentheses can be omitted:
    ActionListener l = event -> xxx;
    
    • The return type of an expression is deduced from the context and does not need to be specified:
    // no expression
    class LenComparator implements Comparator<String>{
        public int compare(String first, String second){ 
            return first.length() - second.length();
    	}
    }
    Arrays.sort(xxx, new LenComparator());
    // After use
    Arrays.sort(xxx, (first, second) -> first.length() - second.length());  
    
    • The deduced type can be indicated using var:
    (@NonNull var first, @NonNull var second)-> first.length() - second.length(); 
    
    • It is illegal for an expression to return a value only in some cases, but not in others:
    (int x)->{
        if(x >= 0){
            return 1;
    	}
        // should also return the value
    }
    
  • A functional interface is an interface with only one abstract method. If you need an object of this interface, you can provide a lambda expression (that is, a lambda expression can be converted into a functional interface):

// The bottom layer will receive an object of a class that implements Comparator<String>, and the content in the expression will be executed after calling the compare method on the object
Array.sort(arr, (first, second)->first.length() - second.length());
  • In lambda expressions, the restrictions on variables are as follows:

    • Only variables whose values ​​do not change can be referenced:
    public static void countDown(int start, int delay){
        ActionListener listener = event -> {
            start--;  // An error is reported, because modifying variables in the expression will cause concurrency security issues
        };
        new Timer(delay, listener).start();
    }
    
    • Variables that change externally cannot be referenced:
    public static void repeat(){
        for(int i = 1; i <= 10; i++){
            System.out.println(i);  // An error is reported, i is constantly changing, so i cannot be captured
        }
        new Timer(1000, listener).start();
    }
    
    • The parameter with the same name as the method local variable cannot be declared in the expression (after all, it is still in the same method and needs to meet the basic requirements):
    public void test(){
        String first = "psj";
        // Error, there is already a first variable
        Comparator<String> comp = (first, second)->first.length() - second.length();  
    }
    
    • The this used in the expression is the this of the method that created the expression:
    public class Application{
        public void init(){
            // The toString method of Application is called
            ActionListener l = event -> System.out.println(this.toString());  
        }
    }
    
  • The point of lambda expression is to delay execution (after all, if you want to execute the code immediately, you don’t need to wrap it in the expression, just write it directly):

3. Inner class

  • Reasons to use inner classes:

    • Inner classes can be hidden from other classes in the same package
    • Inner class methods can access data in the scope in which they are defined, including private data
      • There is an implicit reference to the object of the non-static inner class, which points to the outer class object that instantiates the object (meaning that all the states of the outer object can be accessed); the static inner class does not have this reference
  • Special syntax rules for inner classes:

    • All static fields declared in inner classes must be final
    • Inner classes cannot have static methods
    • Unlike the outer class, the inner class can be declared as private (the inner class can be understood as an attribute of the outer class, and the attribute can of course be private)
    public class Test {
        private class inner{  // can be private
            static int a = 1;  // Report an error, you need to add final and assign a value
            static void test(){}  // Report an error, cannot use static
        }
    }
    
  • Local inner class:

    • Declaring a local inner class cannot use public or private
    • A local inner class is scoped to the block in which it is declared
    • The local inner class is hidden from the outside world (only the ATest method in the code below knows the existence of the innerA class)
    • Local inner classes can access local variables and fields of outer classes
    // The local inner class (innerA) is applicable to this class only appearing in a method (ATest) of the outer class (A).
    public class A{
        String name = "psj";
        public void ATest(int num){
            class innerA{  // The innerA here does not need to inherit a certain class or interface, which is different from the anonymous inner class
                public void innerATest(){
                    System.out.println(num);  // access local variables
                    System.out.println(name);  // Access fields of outer class
                }
            }
            innerA a = new innerA();
            a.innerATest();
        }
    
        public static void main(String[] args) {
            A a = new A();
            a.ATest(10);  // output 10 and psj
        }
    }
    
  • Anonymous inner class: The following code can be understood as creating an object of a class that inherits class B and defines the method innerATest that needs to be implemented

    • An anonymous inner class cannot have a constructor (the constructor is required to be consistent with the class name, it does not even have a class name)
    • An anonymous inner class can provide an object initialization block
    // If you want to create an object of a certain class (B), you don't need to specify a name for the class
    public class A{
        String name = "psj";
        public void ATest(int num){
            var b = new B(){  // The xxx of new xxx() can be an interface or a class
                public void innerATest(){
                    { 
                        // object initialization block 
                    }
                    System.out.println(num);
                    System.out.println(name);
                }
            };
            b.innerATest();
        }
    }
    class B{}
    

Other knowledge points

  • The equals method and compareTo method in the BigDecimal class are incompatible:
BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("1.00");
System.out.println(x.equals(y));  // false, because the precision of the two numbers is different
System.out.println(x.compareTo(y));  // 0 (for equality)
  • Callbacks are a common design pattern that specify actions to take when a particular event occurs

  • For the protected method to be available in the subclass means that the method can be used in the subclass code, not after creating an object of the subclass under other packages (the same is true for the private method, which refers to the code in this class This method can be used in)

// Pack 1
public class A {
    protected void test(){}
}
// Pack 2
public class B extends A {
    // The reason why non-static methods cannot be called directly in static methods is because there is no this pointer, but if a new object is equivalent to having a pointer
    public static void main(String[] args) {
        B b = new B();
        b.test();  // It can be used, because B is a subclass of A, no matter which package B is in, the protected method can be used in its class
    }
}
// Pack 3
public class C {
    public static void main(String[] args) {
        B b = new B();
        b.test();  // An error is reported, because C is not a subclass of A, the test method cannot be called in the code
    }
}
public class A {
    private void test(){}

    public static void main(String[] args) {
        A a = new A();
        a.test();  // can be used, at this time the method is in this class
    }
}
class B{
    public static void main(String[] args) {
        A a = new A();
        a.test();  // report error
    }
}

Tags: Java interface

Posted by gdure on Mon, 02 Jan 2023 06:48:44 +1030