"Think in Java" Reading Notes Volume II

inner class

To create an object of an inner class from any location other than the non-static method of the outer class, you need to specify the object type in the format of outer class. inner class

The inner class has access to all elements of the enclosing class

When an outer class object creates an inner class object, the inner class object secretly captures a reference to that outer class object.
The source code for creating an inner class object in the static method of the outer class is as follows:

public class InnerClass {
    class InnerClass1{
        public InnerClass1() {
            int i1=1;
            System.out.println("InnerClass1");
        }
        public void f1() {
            System.out.println("InnerClass1_f1");
        }
    }
    class InnerClass2{
        int i2=2;
        public InnerClass2() {
            System.out.println("InnerClass2");
        }
        public void f2() {
            System.out.println("InnerClass2_f2");
        }
    }
    public InnerClass1 getInnerClass1() {
        return new InnerClass1();
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        InnerClass.InnerClass1 i1=ic.getInnerClass1();
        i1.f1();

        InnerClass.InnerClass2 i2=ic.new InnerClass2();
        i2.f2();
    }
}

InnerClass1
InnerClass1_f1
InnerClass2
InnerClass2_f2

anonymous inner class

Anonymous class version:

new NoNameClass(){
    public void f3() {
        System.out.println("f3");
    }
}

full version:

    interface INoNameClass{
        public void f3();
    }
    class NoNameClass implements INoNameClass{
        public void f3() {
            System.out.println("f3");
        }
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        INoNameClass innc=ic.new NoNameClass();
    }

Notice:

    abstract class NoNameClass2{
        public NoNameClass2(int i){
            System.out.println("构造器:"+i);
        }
        public abstract void f2();
        //{System.out.println("{     }");}
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        ic.new NoNameClass2(53){
            {System.out.println("{     }");}
            public void f2() {
                System.out.println("f2");
            }
        };
    }

Constructor: 53
{ }

    abstract class NoNameClass2{
        public NoNameClass2(int i){
            System.out.println("构造器:"+i);
        }
        public abstract void f2();
        //{System.out.println("{     }");}
    }
    public static final void main(String...args) {
        InnerClass ic=new InnerClass();
        ic.new NoNameClass2(53){
            {System.out.println("{     }");}
            public void f2() {
                System.out.println("f2");
            }
        };
    }

{ }
constructor: 53

If an anonymous inner class wants to access the outer object, the object needs to be final

Reference Why anonymous inner classes can only access local variables of final type in the method in which they are located? A passage from:

An anonymous inner class cannot access the local variables in the outer class method unless the variable is declared as final type
  1. The "anonymous inner class" mentioned here mainly refers to the instantiation completed when it is defined in the member method of its outer class. A class, if it accesses the local variables in the member method, the local variables must be final modified. The reason is the difficulty of the compiler implementation: the lifetime of the inner class object is likely to exceed the lifetime of the local variables.
  2. The life cycle of local variables: When the method is called, the local variables in the method are created in the stack, and when the method call ends, the stack is removed, and all these local variables die. The inner class object has the same life cycle as other class objects: since an anonymous inner class object is created, the system allocates memory for the object, and it may die until there are no reference variables pointing to the memory allocated to the object (garbage collection by the JVM). ). So it's entirely possible that the member method has ended, the local variable has died, but the object of the anonymous inner class is still alive.
  3. If the object of the anonymous inner class accesses the local variables in the same method, it is required that as long as the anonymous inner class object is alive, those local variables in the stack that it wants to access cannot "die".
  4. Solution: An anonymous inner class object can access local variables defined as final types in the same method. After it is defined as final, the compiler will copy all final type local variables to be accessed by the anonymous inner class object as member variables of the object. In this way, even if the local variable in the stack has died, the anonymous inner class object can still get the value of the local variable, because it copies a copy of itself, and the value of the original local variable is always consistent (the final type is immutable).

Only when the local variable is immutable, that is, final, can the reliability of the data be guaranteed.

nested class

Ordinary inner classes cannot contain static fields and methods, while nested classes can.
Nested classes and static fields and methods exist as soon as they are compiled, and the memory address does not change until GC reclaims them.

class inside interface
public class Staticer implements IStaticer{
    @Override
    public void fun() {
    }
    public static final void main(String...args) {
        IStaticer is=new Staticer();
        is.fun();
    }
}

IStaticer_fun

The role of inner classes

Implementing multiple inheritance when abstract classes exist

public class Multipler extends Multipler1{
    private AMultipler newClass() {
        return new AMultipler(){
            @Override
            public void f1() {
                System.out.println("AMultipler_f1");
            }
        };
    }
    public static final void main(String[] args) {
        Multipler m=new Multipler();
        m.f2();
        AMultipler am=m.newClass();
        am.f1();
    }
}
class Multipler1{
    public void f2() {
        System.out.println("Multipler_f2");
    }
}
abstract class AMultipler{
    public abstract void f1();
}

Multipler_f2
AMultipler_f1

Control frameworks are a special class of application frameworks that address the need to respond to events

Systems that primarily respond to events are called event-driven systems

callback

Class A calls method b of class B, then method b of class B calls method a of class A

interface ICallBacker{
    public void fun();
}
class CallBacker2 implements ICallBacker{
    @Override
    public void fun() {
        System.out.println("CallBacker2_ICallBackers_fun");
    }
}
class CallBacker1{
    public void fun() {
        System.out.println("CallBacker1_fun");
    }
    private class InnerClass implements ICallBacker{
        public void fun() {
            System.out.println("CallBacker1_ICallBackers_fun");
            CallBacker1.this.fun();
        }
    }
    public InnerClass getInnerClass(CallBacker1 cb) {
        return cb.new InnerClass();
    }
}
public class CallBacker{
    public static final void main(String...args) {
        CallBacker1 cb1=new CallBacker1();
        ICallBacker ic1=cb1.getInnerClass(cb1);
        ic1.fun();
        ICallBacker ic2=new CallBacker2();
        ic2.fun();
    }
}

CallBacker1_ICallBackers_fun
CallBacker1_fun
CallBacker2_ICallBackers_fun

A CallBacker1 hook is provided for callback in the fun method of the inner class InnerClass.

Inheritance of inner classes

Since inner classes hold references to enclosing classes, inheritance should be used in the following way

public class InnerExtend extends InnerExtend1.InnerExtend2{
    public InnerExtend(InnerExtend1 ie1) {
        //super();
        ie1.super();
    }
    public static final void main(String...args) {
        InnerExtend1 ie1=new InnerExtend1();
        InnerExtend ie=new InnerExtend(ie1);
    }
}
class InnerExtend1{
    public InnerExtend1() {
        System.out.println("InnerExtend1");
    }
    class InnerExtend2{
        public InnerExtend2() {
            System.out.println("InnerExtend2");
        }
    }
}

InnerExtend1
InnerExtend2

If you change ie1.super() to super(), the following error will be reported:

No enclosing instance of type InnerExtend1 is available due to some intermediate constructor invocation

container

Container interface relationship

Note: The List interface is located in the java.util package, and there is also a List class in the java.awt package

Set: will only be added if the element does not exist

TreeSet: Sort by value size
LinkedHashSet: Sort by added order
HashSet: Distributed randomly

List: Duplicates are not considered, and will be sorted in the order of addition

Container selection:

To do a lot of random access: ArrayList
To insert or delete elements from the middle of the table: LinkedList
Various Queue queues and stack behaviors can be constructed by LinkedList
Note
: Outdated classes such as vector, Hashtable and stack should not be used

    public static final void main(String...args) {
        Vector v=new Vector();
        System.out.print("showSet: ");
        v.showSet();
        System.out.println();
        System.out.print("showList: ");
        v.showList();
    }
    private void showList() {
        Collection<Integer> cl=new ArrayList<Integer>();
        Collection<Integer> cls=new ArrayList<Integer>();
        cls.addAll(Arrays.<Integer>asList(1,2,3,4,5));
        Collections.addAll(cls, 6,7,8,9,10);
        cl.add(1);
        cl.add(1);
        cl.add(2);
        cl.add(3);
        cl.add(8);
        cl.add(5);
        for(Integer i:cl) {
            System.out.print(i+" ");
        }
        System.out.print("|");
        for(Integer i:cls) {
            System.out.print(i+" ");
        }
    }
    private void showSet() {
        Collection<Integer> cl=new LinkedHashSet<Integer>();
        Collection<Integer> clt=new TreeSet<Integer>();
        cl.add(1);
        cl.add(1);
        cl.add(2);
        cl.add(3);
        cl.add(8);
        cl.add(5);
        clt.addAll(Arrays.asList(1,7,3,6,3));
        for(Integer i:cl) {
            System.out.print(i+" ");
        }
        System.out.print("|");
        for(Integer i:clt) {
            System.out.print(i+" ");
        }
    }

showSet: 1 2 3 8 5
showList: 1 1 2 3 8 5 | 1 2 3 4 5 6 7 8 9 10 |

In the follow-up, we will explore the algorithm implementation and performance differences between the sets

Containers and Iterators

Note: The dotted line box represents the interface, the solid line box represents the class, the dotted line of the hollow arrow represents that the class implements the interface, and the solid arrow represents that a class can produce the object of the class pointed to by the arrow.

iterator

Iterators are also a design pattern for lightweight objects

Don't worry about numbers and types:

    private void showIterator() {
        List<Integer> l=new ArrayList<Integer>();
        for(int i=0;i<5;i++) {
            l.add(i);
        }
        Iterator<Integer> i=l.iterator();
        Set<Integer> s=new HashSet<Integer>();
        for(int j=0;j<5;j++) {
            s.add(j);
        }
        display(s.iterator());
        display(l.iterator());
        i=l.iterator();
        while(i.hasNext()) {
            i.next();
            i.remove();
        }
        System.out.println(l.toString());
    }
    private void display(Iterator i) {
        while(i.hasNext()) {
            System.out.print(i.next()+" ");
        }
        System.out.print("\n");
    }

0 1 2 3 4
0 1 2 3 4
[]

Note: The iterator object needs to call next first to be the first data in the list container

ListIterator

An iterator that is only suitable for bidirectional traversal of the List container

stack (stack stack)

A last-in-first-out (LIFO) container implements stack storage
with LinkedList:

public class Stacker {
    public static final void main(String...args) {
        String str="";
        MyStack ms=new MyStack();
        List<String> l=new ArrayList<String>(Arrays.asList("+","U","+","n","+","x","-","-"));;
        System.out.println(l.toString());
        Iterator i=l.iterator();
        while(i.hasNext()) {
            str=(String) i.next();
            if(str.equals("+")) {
                ms.push(i.next());
            }
            else if(str.equals("-")) {
                ms.pop();
            }
        }
        System.out.println(ms.toString());
    }
}
class MyStack<T>{
    public MyStack() {  
    }
    LinkedList<T> stack=new LinkedList<T>();
    public void push(T t) {
        stack.add(t);
    }
    public T pop() {
        //先进后出特性
        return stack.removeLast();
    }
    public boolean isEmpty() {
        return stack.isEmpty();
    }
    public String toString() {
        return stack.toString();
    }
}

[+, U, +, n, +, x, -, -]
[x]

queue

A typical first-in-first-out (FIFO) container

LinkedList is upcast to Queue to implement queue

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
public class Queuer {
    static void printer(Queue q) {
        while(q.peek()!=null) {
            //先进先出特性
            System.out.print(q.remove()+" ");
        }
        System.out.println();
    }
    public static final void main(String...args) {
        Random rand=new Random(53);
        Queue q=new LinkedList<Integer>();
        int r=0;
        for(int i=0;i<10;i++) {
            r=rand.nextInt(20);
            q.offer(r);
            System.out.print(r+" ");
        }
        System.out.println();
        printer(q);
    }
}

16 7 16 1 8 15 12 2 10 0
16 7 16 1 8 15 12 2 10 0

Use of PriorityQueue

PriorityQueue
This class can set the priority in the queue elements

import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
public class Queuer {
    public static final void main(String...args) {
        comparatorer();
    }
    private static void comparatorer() {
        Comparator<Oer> comparator=new Comparator<Oer>() {
            @Override
            public int compare(Oer o1, Oer o2) {
                // TODO Auto-generated method stub
                if(o1.getPriority()>o2.getPriority()) {
                    //o2
                    return -1;
                }
                else if(o2.getPriority()>o1.getPriority()) {
                    //o1
                    return 1;
                }
                return 0;
            }
        };
        Oer o1=new Oer("o1",4);
        Oer o2=new Oer("o2",53);
        PriorityQueue<Oer> pq=new PriorityQueue<Oer>(2,comparator);
        pq.offer(o1);
        pq.offer(o2);
        System.out.println(pq.toString());
    }
}
class Oer{
    private int priority;
    private String name;
    public Oer(String name,int priority) {
        this.priority=priority;
        this.name=name;
    }
    @Override
    public String toString(){
        return name;
    }
    public int getPriority() {
        return priority;
    }
}

[o2, o1]

Override the iteration class by inheriting from AbstractCollection

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class Collectioner {
    public static final void main(String...args) {
        List<Integer> list=new ArrayList<Integer>();
        list.addAll(Arrays.asList(1,2,3,4,5));
        Collectioner_child cc=new Collectioner_child(list);
        Iterator<Integer> i=cc.iterator();
        System.out.println(i.next());
    }
}
class Collectioner_child extends AbstractCollection{
    List<Integer> list;
    public Collectioner_child(List<Integer> list) {
        this.list=list;
    }
    @Override
    public Iterator iterator() {
        // TODO Auto-generated method stub
        return new Iterator() {
            private int index;
            @Override
            public boolean hasNext() {
                // TODO Auto-generated method stub
                return index < list.size();
            }
            @Override
            public Object next() {
                // TODO Auto-generated method stub
                return list.get(index++);
            }
        };
    }
    @Override
    public int size() {
        // TODO Auto-generated method stub
        return list.size();
    }
}

1

If you directly inherit the Collection interface, you need to implement a large number of methods, and the abstract class of AbstrctCollection that has implemented the Collection method only needs to implement two more abstract methods.
Through this example, you can further understand the use of iterators.

Custom foreach rule

The first (create a custom iterator class that inherits from ArrayList)

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Iteratorer {
    public Iteratorer() {

    }
    public static final void main(String...args) {
        List<String> list=new ArrayList<String>(Arrays.asList("12","33","22"));
        MyIterator<String> mi=new MyIterator<String>(list);
        for(String i:mi) {
            System.out.print(i+" ");
        }
        System.out.print("\n");
        for(String i:mi.reversed()) {
            System.out.print(i+" ");
        }
        System.out.println();
        //java 8中的迭代循环
        mi.reversed().forEach(System.out::print);
    }

}
class MyIterator<T> extends ArrayList<T>{
    public MyIterator(List<T> list) {
        super(list);
    }
    public Iterable<T> reversed() {
        return new Iterable<T>() {
            @Override
            public Iterator<T> iterator() {
                // TODO Auto-generated method stub
                return new Iterator<T>() {
                    int current=size()-1;
                    @Override
                    public boolean hasNext() {
                        // TODO Auto-generated method stub
                        return current>-1;
                    }
                    @Override
                    public T next() {
                        // TODO Auto-generated method stub
                        return get(current--);
                    }
                };
            }
        };
    }   
}

12 33 22
22 33 12
223312

The second (implementing the Iterator and Iterable interfaces directly in the main class)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Iterator2 implements Iterator<String>,Iterable<String>{
    private List<String> list;
    private int size;
    public static final void main(String...ags) {
        Iterator2 i2=new Iterator2();
        i2.list=new ArrayList<String>();
        i2.list.addAll(Arrays.asList("a","v","c","d"));
        i2.size=i2.list.size();
        for(String s:i2) {
            System.out.print(s+" ");
        }
    }

    @Override
    public Iterator<String> iterator() {
        // TODO Auto-generated method stub
        return this;
    }

    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        return size>0;
    }

    @Override
    public String next() {
        // TODO Auto-generated method stub
        return list.get(--size);
    }

}

d c v a

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325586404&siteId=291194637