This is the 31st day of my participation in the August Text Challenge.More challenges in August

A preface

Many books say that in the Java world, everything is an object. In a sense, there are two kinds of objects in Java: instance objects and Class objects. An instance object is an instance of a class we normally define:

public class Person {}Copy the code

Then use the new keyword:

public class Person {
    public static void main(String[] args){
        Person p = newPerson(); }}Copy the code

A Class object cannot be obtained with the new keyword because it is generated by the JVM to hold information about the corresponding Class. In other words, when we define a Class file and compile it into.class bytecode, the compiler also creates a Class object for us and stores it in the.class file. I don’t know if that’s the right way to describe it, because I’ve seen some books call.class files class objects. There is also a classloading mechanism within the JVM that loads. Class files and corresponding class objects into memory when needed (lazy loading). It’s important to keep in mind that when a Person. Java file is compiled into a Person.class, it also generates a corresponding class object.

The acquisition of two Class objects

Class objects are used by the JVM to hold information about instance objects. Otherwise, we can treat a Class object as a generic instance object. In fact, all Class objects are instances of Class. There are three ways to get the corresponding Class object of an instance: 1. Use the getClass() method of the instance variable:

        Dog dog = new Dog();
        Class d = dog.getClass();  
Copy the code

Class forName();

        try {
            Class dog1 = Class.forName("Dog");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
Copy the code

Class = “.class “;

Class dog2 = Dog.class;
Copy the code

Use and reflection of Class objects

The JAVA reflection mechanism allows you to know all the properties and methods of any class in the running state. For any object, you can call any of its methods and properties; This ability to dynamically retrieve information and invoke methods on objects is called the Reflection mechanism of the Java language.

In short, we can reverse from.class to.java(decomcompile), we can use reflection to access the properties and methods of a Java-like object, and we can even easily change a private member. Looking at the code, let’s define a Cat class first:

class Cat{
    public static int count;
    public int age;
    private String name;
    
    static {
        count = 0;
    }
    
    public Cat(a){
        age = count++;
        System.out.println("this is class Cat!");

    }
    
    public void run(a){}private void ruff(a){}}Copy the code

Notice that our class contains static members, private variables, static initializers, and private methods. A reference to lazy loading: when cat.java is compiled into a cat.class file, it is not immediately loaded into memory, but is loaded when its static members are first accessed (so the default constructor for Cat is also static!).

 Class c = Cat.class;
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields){
            System.out.println(field);
        }
Copy the code

The results are as follows:

public static int Cat.count
public int Cat.age
private java.lang.String Cat.name
Copy the code

Class Cat = Cat; class Cat = Cat;

Method[] methods = c.getDeclaredMethods();
        for (Method method : methods){
            System.out.println(method);
        }
Copy the code

The results are as follows:

public void Cat.run()
private void Cat.ruff()
Copy the code

It’s funny that we can get information about a class at runtime. At the same time, we found that the static initialization snippet in the Cat class was not executed. Next we use the Class object to get the corresponding instance object:

        try {
            Cat cat = (Cat) c.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
Copy the code

The static code block executes:

this is class Cat!
Copy the code

Now let’s do something amazing:

try {
            Class catClass = Class.forName("Cat");
            Field name = catClass.getDeclaredField("name");
            name.setAccessible(true);
            Cat cat2 = (Cat) catClass.newInstance();
            name.set(cat2,"xxx");
            System.out.println(cat2.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
Copy the code

This time we use class.forname () to get the Class object, which tells the JVM to find and load the specified Class, meaning that a static block of code for the Cat Class will be executed. The second thing to note is that we access the name attribute that would otherwise not be accessible through several methods of Class:

this is class Cat!
xxx
Copy the code

In this sense, reflection doesn’t fit the idea of OOP, so we use this feature only when necessary.

Four afterword.

Understanding Class objects will not only help us understand the idea that everything is an object, but it will also help us learn about generics, type erasure, and Java reflection where appropriate.