🍋1.Java代码初始化顺序
Java的语言中,当我们去实例化对象时(也就是通常说的new对象),对象所在类的所有成员变量首先都要被初始化,只有这个类所有成员变量完成初始化后,才会调用该类的构造方法去创建对象。
Java的初始化顺序一般都遵循着一下三个原则(从高到底):
1.静态对象(被static修饰的变量)优先于非静态对象初始化,而且静态对象只会被初始化一次,而非静态对象可能会多次初始化
2.父类总是优先于子类初始化(就是当你实例化A类对象时,发现A类有个父类B类,我们必须得先初始化B了才能回来初始化A)
3.按照成本变量定义的顺序进行初始化。即使变量定义的很分散,它们仍然会按照从头到尾的顺序去完成初始化。
但是Java程序的初始化工作可以在不同的代码块中来完成(比如:静态代码块、构造方法等),它们执行的顺序是一个非常总要的核心,执行的顺序为:
父类静态变量->父类静态代码块->子类静态变量->子类静态代码块->父类非静态变量->父类非静态代码块->父类构造方法->子类非静态变量->子类非静态代码块->子类构造方法。
我们通过一个例子来帮助大家记忆:
public class Son extends father { static { System.out.println("子类静态代码块"); } { System.out.println("子类非静态代码块"); } public Son() { System.out.println("子类构造方法"); } } class father{ static { System.out.println("父类静态代码块"); } { System.out.println("父类非静态代码块"); } public father() { System.out.println("父类构造方法"); } }
下面是主函数和输出顺序:
public static void main(String[] args) { new Son(); }
可以发现输出结果完全符合我们上面的顺序。其实这也非常好记忆,无论是子类还是父类,都是优先静态后非静态,子类除了静态代码块能紧跟父类静态代码块,其他全都是落后于父类执行。
☀️2.Java反射
Java为什么强大?我相信需要人都知道是由于Java的反射机制。反射机制是指对于处在运行中的类,都能够获取到这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意一个以及访问它的属性;这种通过动态获取类或对象的属性以及方法从而完成调用功能就被称之为Java语言的反射。Java许多强大的框架,如ssm+springboot都是基于反射机制的强大而实现的。反射主要有以下四个功能:
获取类的访问修饰符、方法、属性以及父类信息
在运行时根据类的名字创建对象。可以在运行时调用任意一个对象的方法
在运行时判断一个对象属于哪个类
生成动态代理
Java中万物皆为类,反射中也存在一个非常非常重要的类——Class。在Java语言中获取Class对象的主要方法有以下几种:
1.通过className.class获取。通过类名.class直接获得Class对象
public class test { public static void main(String[] args) { Class<A> aClass = A.class; System.out.println(aClass); } } class A{ }
2. 通过Class.forName()来获取
public class test { public static void main(String[] args) throws ClassNotFoundException { Class<?> a = Class.forName("wangdao5.A"); System.out.println(a); } } class A{ }
我这里的wangdao5是我的包名,如果你使用这个方法时出现ClassNotFound的异常,在你的类名前加上包名即可。
3.通过Object.getClass()来获取
public class test { public static void main(String[] args) throws ClassNotFoundException { Class<?> a = new A().getClass(); System.out.println(a.getName()); } } class A{ }
上面就是我们常见的三种获取类的Class对象的方式,肯定有同学好奇这有啥区别呢?看上去感觉都差不多。别急,它们还是有区别的:
方法1不执行静态块和动态构造代码块
方法2只执行静态块,而不执行动态构造块
因为需要创建对象,所以会执行静态块和动态块
Class类之所以强大,是因为它提供了非常非常多的方法,下面给大家举例三类常用的方法。
1.获取类的构造方法
构造方法的封装类为Constructor,Class类中有如下四个方法来获得Constructor对象:
public Constructor<?>[] getConstructors():返回类的所有的public构造方法
public Constructor<T> getConstructor(Class<?>...parameterTypes):返回指定的public构造方法;
public Constructor<?>[] getDeclaredConstructors();返回类的所有的构造方法
public Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):返回指定的构造方法
2.获取类的成员变量的方法
成员变量的封装类为Field类,Class类提供了以下四个方法来获取Field对象:
public Field[] getFields():获取类的所有的public成员变量
public Field getField(String name):获取指定的public成员变量
public Field[] getDeclaredFields():获取类的所有的成员变量
public Field getDeclaredField(Strig name):获取任意访问权限的指定名字的成员变量
3.获取类的方法
public Method[] getMethods:获取所有的public方法
public Mehod[] getDeclaredMethods():获取所有的方法
public Method getDeclareMethod(Stirng name,Class<?>...parameterTypes)获取指定的方法