[Use of Inner Class & Anonymous Inner Class & Reflection & Lambda & Stream]

1. Inner class and anonymous inner class

The main difference between anonymous inner classes and lambda expressions is that
1. An anonymous inner class must implement all methods of the inherited class
2. Anonymous inner classes have an override flag when rewriting, but lambdas do not
3. The interface inherited by the lambda expression can only have one abstract method

In the process of using anonymous inner classes, we need to pay attention to the following points:

  • 1. When using an anonymous inner class, we must inherit a class or implement an interface, but we cannot have both, and we can only inherit a class or implement an interface.
  • 2. Constructors cannot be defined in anonymous inner classes.
  • 3. There cannot be any static member variables and static methods in the anonymous inner class.
  • 4. The anonymous inner class is a local inner class, so all the restrictions of the local inner class are also valid for the anonymous inner class.
  • 5. An anonymous inner class cannot be abstract, it must implement all the abstract methods of the inherited class or implemented interface.

Anonymous inner class: A new class is defined inside the class

Classification of inner classes:
static inner class
instance inner class
local inner class
Actually use inner class to write the code, the readability is too poor

public interface Skill {<!-- -->
    void use(); // abstract method to release skills
}

public class SkillImpl implements Skill {<!-- -->
    @Override
    public void use() {<!-- -->
        System.out.println("Biu~biu~biu~");
    }
}

public class Hero {<!-- -->
    private String name; // hero's name
    private Skill skill; // hero's skill
    public Hero() {<!-- -->
    }
    public Hero(String name, Skill skill) {<!-- -->
        this.name = name;
        this.skill = skill;
    }
    public void attack() {<!-- -->
        System.out.println("My name is " + name + ", start casting skills:");
        skill.use(); // call the abstract method in the interface
        System.out.println("Skill cast completed.");
    }
    public String getName() {<!-- -->
        return name;
    }
    public void setName(String name) {<!-- -->
        this.name = name;
    }
    public Skill getSkill() {<!-- -->
        return skill;
    }
    public void setSkill(Skill skill) {<!-- -->
        this.skill = skill;
    }
}

Use anonymous objects or anonymous inner classes to implement calls

public class DemoGame {<!-- -->

    public static void main(String[] args) {<!-- -->
        Hero hero = new Hero();
        hero.setName("Ash"); // Set the hero's name

        // set hero skills
        hero.setSkill(new SkillImpl()); // Use a separately defined implementation class

        //You can also use an anonymous inner class instead
        Skill skill = new Skill() {<!-- -->
            @Override
            public void use() {<!-- -->
                System.out.println("Pia~pia~pia~");
            }
        };
        hero. setSkill(skill);
}

Use both anonymous inner classes and anonymous objects

 // Simplify further, using both anonymous inner classes and anonymous objects
        hero.setSkill(new Skill() {<!-- -->
            @Override
            public void use() {<!-- -->
                System.out.println("Biu~Pia~Biu~Pia~");
            }
        });

        hero. attack();
    }

2. Reflection

The main principle of reflection is to call the corresponding constants and methods through characters: eg, unload the method name and variable name from the .properties file
        The way to get the Class object:
            1. Class.forName("full class name"): Load the bytecode file into memory and return the Class object
            2. Class name.class: obtained through the attribute class of the class name
            3. Object.getClass(): The getClass() method is defined in the Object class.
 Class object function:
         * Get function:
         1. Get member variables
             * Field[] getFields() Get all public modified member variables
             * Field getField(String name) Get the member variable of the specified public modification

             * Field[] getDeclaredFields() Get all member variables, regardless of modifiers
             * Field getDeclaredField(String name)
         2. Get constructors
             * Constructor<?>[] getConstructors()
             * Constructor<T> getConstructor(class<?>... parameterTypes)

             * Constructor<T> getDeclaredConstructor(class<?>... parameterTypes)
             * Constructor<?>[] getDeclaredConstructors()
         3. Get member methods:
             * Method[] getMethods Get all public modified methods
             * Method getMethod(String name, class<?>... parameterTypes)

             * Method[] getDeclaredMethods()
             * Method getDeclaredMethod(String name, class<?>... parameterTypes)

         4. Get the class name
             * String getName()

1. Get member variables

Person.classes omitted. . write it yourself
getFields()

public static void main(String[] args) throws Exception {<!-- -->

        //0. Get the Class object of Person
        Class personClass = Person. class;
        
        //1.Field[] getFields() gets all public modified member variables
        Field[] fields = personClass. getFields();
        for (Field field : fields) {<!-- -->
            System.out.println(field);
        }

getField()

 //2.Field getField(String name)
        Field a = personClass. getField("a");
        //Get the value of member variable a
        Person p = new Person();
        Object value = a. get(p);
        System.out.println(value);
        //Set the value of a
        a.set(p,"Zhang San");
        System.out.println(p);

getDeclaredFields() & & getDeclaredField()

 //Field[] getDeclaredFields(): Get all member variables, regardless of modifiers
        Field[] declaredFields = personClass. getDeclaredFields();
        for (Field declaredField : declaredFields) {<!-- -->
            System.out.println(declaredField);
        }
        //Field getDeclaredField(String name)
        Field getd = personClass. getDeclaredField("d");
        //Ignore security checks for access modifiers
        getd.setAccessible(true);//violent reflection
        Object value2 = getd.get(p);//Get the value of getd from the p object
        System.out.println(value2);

2. Get constructors

Constructor with parameters getConstructor(class… parameterTypes)

 public static void main(String[] args) throws Exception {<!-- -->

        //0. Get the Class object of Person
        Class personClass = Person. class;

        // Constructor with parameters
        //Constructor<T> getConstructor(class<?>... parameterTypes)
        Constructor constructor = personClass. getConstructor(String. class, int. class);
        //Create object
        Object person = constructor.newInstance("Zhang San", 23);
        System.out.println(person);

No-argument constructor getConstructor()

 //Method 1
        // no parameter constructor
        Constructor constructor1 = personClass. getConstructor();
        System.out.println(constructor1);
        //Create object
        Object person1 = constructor1. newInstance();
        System.out.println(person1);
\t\t
//Method 2
        // Directly create a constructor with no parameters
        Object o = personClass. newInstance();
        System.out.println(o);

3. Get member methods

Get method without parameters

public static void main(String[] args) throws Exception {<!-- -->

        //0. Get the Class object of Person
        Class personClass = Person. class;
        // method to get the specified name
        Method eat_method = personClass. getMethod("eat");
        Person p = new Person();
        //Execution method eat() method
        eat_method.invoke(p);

Get the parameterized method getMethod()

 //Execute the crime with a String
        Method eat_method2 = personClass. getMethod("eat", String. class);
        //execution method
        eat_method2.invoke(p,"rice");

Get all public modified methods: getMethods()

 //Get all public modification methods
        Method[] methods = personClass. getMethods();
        for (Method method : methods) {<!-- -->
            System.out.println(method);
            String name = method. getName();
            System.out.println(name);
            //method.setAccessible(true);
        }

4. Get the class name

//Get the class name
        String className = personClass. getName();
        System.out.println(className);//cn.itcast.domain.Person

5. Test reflection, get the method through the Properties() object

The pro.properties file is created by itself

public class ReflectTest {<!-- -->
    public static void main(String[] args) throws Exception {<!-- -->
        //1. Load the configuration file
        //1.1 Create Properties object
        Properties pro = new Properties();
        //1.2 Load the configuration file and convert it to a collection
        //1.2.1 Get the configuration file in the class directory
        ClassLoader classLoader = ReflectTest. class. getClassLoader();
        InputStream is = classLoader. getResourceAsStream("pro. properties");
        pro.load(is);

        //2. Get the data defined in the configuration file
        String className = pro. getProperty("className");
        String methodName = pro. getProperty("methodName");


        //3. Load this class into memory
        Class cls = Class. forName(className);
        //4. Create an object
        Object obj = cls. newInstance();
        //5. Get the method object
        Method method = cls. getMethod(methodName);
        //6. Execution method
        method.invoke(obj);
    }
}

compile successfully
No: Compilation failed (there is no abstract method in the interface and the number of abstract methods exceeds 1)

```java
@FunctionalInterface
public interface MyFunctionalInterface {
    //Define an abstract method
    public abstract void method();
}

public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{<!-- -->
    @Override
    public void method() {<!-- -->

    }
}

3. Functional interface, generally used with Lambda expressions

(1) There must be an interface to use Lambda, and the interface has only one abstract method (that is, a functional interface).

(2) Lambda must be able to “context infer” (that is, infer the parameter type according to the context, which is also an advantage of Lambda, so that the parameter type can be omitted and more concise)

shortcoming:
(1) It is not easy to debug in debug mode;
(2) It is inconvenient to force type conversion in the lambda statement;
(3) You cannot modify the value outside forEach in foreach
(4) If it is not calculated in parallel, the calculation speed is not as good as the traditional for loop in many cases.

 Functional interface: an interface with and only one abstract method is called a functional interface
    Of course, the interface can contain other methods (default, static, private)

    @FunctionalInterface annotation
    Function: It can detect whether the interface is a functional interface
        Yes: Compiled successfully
        No: Compilation failed (there is no abstract method in the interface and the number of abstract methods exceeds 1)
@FunctionalInterface
public interface MyFunctionalInterface {<!-- -->
    //Define an abstract method
    public abstract void method();
}

public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{<!-- -->
    @Override
    public void method() {<!-- -->

    }
}

1. The parameter of the method is an interface, so we can pass the anonymous inner class of the interface [the function of the anonymous inner is to reduce the writing of the implementation class]

public class Demo {<!-- -->
    //Define a method, the parameter uses the functional interface MyFunctionalInterface
    public static void show(MyFunctionalInterface myInter){<!-- -->
        myInter. method();
    }

    public static void main(String[] args) {<!-- -->
        //Call the show method, the parameter of the method is an interface, so the implementation class object of the interface can be passed
        show(new MyFunctionalInterfaceImpl());

        //Call the show method, the parameter of the method is an interface, so we can pass the anonymous inner class of the interface
        show(new MyFunctionalInterface() {<!-- -->
            @Override
            public void method() {<!-- -->
                System.out.println("Use the anonymous inner class to override the abstract method in the interface");
            }
        });
    }
}

2. Use Lambda expressions to rewrite the method() method [() represents the method() method]

 //Call the show method, the parameter of the method is a functional interface, so we can use Lambda expression
        show(()->{<!-- -->
            System.out.println("Use Lambda expression to rewrite the abstract method in the interface");
        });

        // Simplify the Lambda expression
        show(()-> System.out.println("Use Lambda expression to rewrite the abstract method in the interface"));

4. Detailed introduction of Stream

Detailed introduction of Stream All Collection collections can obtain stream through the default method of stream;

https://blog.csdn.net/qq_41821963/article/details/125364126

public class Demo02Stream {<!-- -->
    public static void main(String[] args) {<!-- -->
        //Create a List collection to store the name
        List<String> list = new ArrayList<>();
        list.add("Zhang Wuji");
        list.add("Zhou Zhiruo");
        list.add("Zhao Min");
        list.add("Zhang Qiang");
        list.add("Zhang Sanfeng");

        //Filter the elements in the list collection, as long as the elements starting with Zhang are stored in a new collection
        //Filter the listA collection, as long as the name length is 3, store it in a new collection
        //traverse listB collection
        list. stream()
                .filter(name->name.startsWith("Zhang"))
            .filter(name->name.length()==3)
            .forEach(System.out::println);
}
}

Convert collection to Stream

1. In the ArrayList collection

public class Demo01GetStream {<!-- -->
    public static void main(String[] args) {<!-- -->
        //Convert the collection to a Stream
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list. stream();
    }
}

2. In the Set collection

 Set<String> set = new HashSet<>();
         Stream<String> stream2 = set. stream();

3. Acquisition of key and value in the HashMap collection of key-value pairs

 Map<String,String> map = new HashMap<>();
        // Get the key and store it in a Set collection
        Set<String> keySet = map. keySet();
        Stream<String> stream3 = keySet. stream();

        // Get the value and store it in a Collection
        Collection<String> values = map. values();
        Stream<String> stream4 = values. stream();

4. Obtain key-value pairs (the mapping relationship between key and value entrySet)

 //Get the key-value pair (the mapping relationship between key and value entrySet)
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> stream5 = entries.stream();

5. Convert the array to Stream

 //Convert the array to Stream
        Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5);
        
        //Variable parameters can pass arrays
        Integer[] arr = {<!-- -->1,2,3,4,5};
        Stream<Integer> stream7 = Stream.of(arr);
        String[] arr2 = {<!-- -->"a","bb","ccc"};
        Stream<String> stream8 = Stream.of(arr2);

6. forEach

Common method in Stream _forEach
void forEach(Consumer<? super T> action);
This method receives a Consumer interface function, and will hand over each stream element to the function for processing.
The Consumer interface is a consumption-type functional interface, which can pass Lambda expressions and consume data

according to

 public static void main(String[] args) {<!-- -->
        //Get a Stream
        Stream<String> stream1 = Stream.of("Zhang San", "Li Si", "Wang Wu", "Zhao Liu", "Tian Qi");
        //Use the method forEach in the Stream to traverse the data in the Stream
        /*stream.forEach((String name)->{
            System.out.println(name);
        });*/

        stream1.forEach(name->System.out.println(name));
    }

7, filter

Common method in Stream _filter: used to filter data in Stream
Stream<T> filter(Predicate<? super T> predicate);
The parameter Predicate of the filter method is a functional interface, so Lambda expressions can be passed to filter the data
Abstract method in Predicate:
    boolean test(T t);
 Stream<String> stream = Stream.of("Zhang Sanfeng", "Zhang Cuishan", "Zhao Min", "Zhou Zhiruo", "Zhang Wuji");
        //Filter the elements in the Stream, as long as the person surnamed Zhang
        Stream<String> stream2 = stream.filter((String name)->{<!-- -->return name.startsWith("Zhang");});
        //traverse stream2 stream
        stream2.forEach(name->System.out.println(name));

7, map

Common method _map in Stream stream: used for type conversion
If you need to map elements from one stream to another stream, you can use the map method.
Stream map(Function mapper);
This interface requires a Function function interface parameter, which can convert the T-type data in the current stream to another R-type stream.
Abstract method in Function:
R apply(T t);

 //Get a Stream of String type
        Stream<String> stream = Stream.of("1", "2", "3", "4");
        //Use the map method to convert (map) an integer of string type to an integer of type Integer
         stream.map((String s)->{<!-- -->
            return Integer. parseInt(s);
        }).forEach((i->System.out.println(i)));
        
         //shorthand
        stream.map(Integer::parseInt).forEach((System.out::println));

8, count

Common method _count in Stream: used to count the number of elements in Stream
long count();
The count method is a terminal method, and the return value is an integer of type long
So you can no longer call other methods in the Stream stream
 ArrayList<Integer> list = new ArrayList<>();
        list. add(1);
        list. add(2);
        list. add(3);
        list. add(4);
        list. add(5);
        list. add(6);
        list. add(7);
        Stream<Integer> stream = list. stream();
        long count = stream. count();
        System.out.println(count);//7

9, limit

Common method _limit in Stream: used to intercept elements in the stream
The limit method can intercept the stream and only use the first n. Method signature:
Stream<T> limit(long maxSize);
    The parameter is a long type, if the current length of the collection is greater than the parameter, it will be intercepted; otherwise, no operation will be performed
The limit method is a delay method, which just intercepts the elements in the stream and returns a new stream, so you can continue to call other methods in the Stream stream
 String[] arr = {<!-- -->"Beautiful Sheep", "Joyful", "Lazy", "Grey Wolf", "Red Wolf"};
        Stream<String> stream = Stream.of(arr);
        //Use limit to intercept the elements in the Stream, as long as the first 3 elements
        Stream<String> stream2 = stream. limit(3);
        //traverse stream2 stream
        stream2.forEach(name->System.out.println(name));

10, skip

Common method _skip in Stream: used to skip elements
If you want to skip the first few elements, you can use the skip method to get a new stream after interception:
Stream<T> skip(long n);
If the current length of the stream is greater than n, the first n streams are skipped; otherwise, an empty stream of length 0 will be obtained.
 String[] arr = {<!-- -->"Beautiful Sheep", "Joyful", "Lazy", "Grey Wolf", "Red Wolf"};
        Stream<String> stream = Stream.of(arr);
        //Use the skip method to skip the first 3 elements
        Stream<String> stream2 = stream.skip(3);
        //traverse stream2 stream
        stream2.forEach(name->System.out.println(name));

11, concat

Common methods in Stream stream_concat: used to combine streams together
If you have two streams and want to merge them into one stream, you can use the static method concat static Stream of the Stream interface
concat(Stream a, Stream b)

 //Create a Stream stream
        Stream<String> stream1 = Stream.of("Zhang Sanfeng", "Zhang Cuishan", "Zhao Min", "Zhou Zhiruo", "Zhang Wuji");
        //Get a Stream
        String[] arr = {<!-- -->"Beautiful Sheep","Joyful","Lazy","Grey Wolf","Red Wolf"};
        Stream<String> stream2 = Stream.of(arr);
        // Combine the above two streams into one stream
        Stream<String> concat = Stream. concat(stream1, stream2);
        //traverse the concat stream
        concat.forEach(name->System.out.println(name));

Exercise: Collection element processing (Stream mode)

Replace the traditional for loop writing method in the previous question with the Stream streaming method.
The initial contents of the two collections are unchanged, as is the definition of the Person class.

public class Demo02StreamTest {<!-- -->
    public static void main(String[] args) {<!-- -->
        //first team
        ArrayList<String> one = new ArrayList<>();
        one.add("Di Lieba");
        one.add("Song Yuanqiao");
        one.add("Su Xinghe");
        one.add("Shi Potian");
        one.add("Jade in the stone");
        one.add("Lao Tzu");
        one.add("Zhuangzi");
        one.add("Hong Qigong");
        //1. The first team only needs the name of the member whose name is 3 characters; store it in a new collection.
        //2. After the first team is screened, only the first 3 people are required; store it in a new collection.
        Stream<String> oneStream = one. stream(). filter(name -> name. length() == 3). limit(3);

        // second team
        ArrayList<String> two = new ArrayList<>();
        two.add("Guli Nazha");
        two.add("Zhang Wuji");
        two.add("Zhao Liying");
        two.add("Zhang Sanfeng");
        two.add("Nicholas Zhao Si");
        two.add("Zhang Tianai");
        two.add("Zhang Ergou");
        //3. The second team only needs the name of the member whose surname is Zhang; store it in a new collection.
        //4. After the second team is screened, don't want the first 2 people; store it in a new collection.
        Stream<String> twoStream = two.stream().filter(name -> name.startsWith("Zhang")).skip(2);

        //5. Merge the two teams into one team; store into a new collection.
        //6. Create a Person object based on the name; store it in a new collection.
        //7. Print the Person object information of the entire team.
        Stream.concat(oneStream, twoStream).map(name->new Person(name)).forEach(p->System.out.println(p));
        Stream.concat(oneStream,twoStream).map(Person::new).forEach(System.out::println);

    }
}

output:
Person{name=’Song Yuanqiao’}
Person{name=’Su Xinghe’}
Person{name=’Shi Potian’}
Person{name=’Zhang Tianai’}
Person{name=’Zhang Ergou’}