[Java]Day12:类加载器,反射,枚举,注解

tech2022-09-20  75

1.类加载器

作用

负责将.class文件(存储的物理文件)加载在到内存中

类加载过程

加载

通过包名 + 类名,获取这个类,准备用流进行传输在这个类加载到内存中加载完毕创建一个class对象

1.2类加载的分类

分类

Bootstrap class loader:虚拟机的内置类加载器,通常表示为null ,并且没有父nullPlatform class loader:平台类加载器,负责加载JDK中一些特殊的模块System class loader:系统类加载器,负责加载用户类路径上所指定的类库

类加载器的继承关系

System的父加载器为PlatformPlatform的父加载器为Bootstrap

1.3ClassLoader 中的两个方法

方法介绍

方法名说明public static ClassLoader getSystemClassLoader()获取系统类加载器public InputStream getResourceAsStream(String name)加载某一个资源文件

示例代码

public class ClassLoaderDemo2 { public static void main(String[] args) throws IOException { //static ClassLoader getSystemClassLoader() 获取系统类加载器 //InputStream getResourceAsStream(String name) 加载某一个资源文件 //获取系统类加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); //利用加载器去加载一个指定的文件 //参数:文件的路径(放在src的根目录下,默认去那里加载) //返回值:字节流。 InputStream is = systemClassLoader.getResourceAsStream("prop.properties"); Properties prop = new Properties(); prop.load(is); System.out.println(prop); is.close(); } }

2.反射

2.1反射的概述

反射机制

是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意属性和方法; 这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

2.2获取Class类对象的三种方式

三种方式分类

类名.class属性

对象名.getClass()方法

Class.forName(全类名)方法

示例代码 public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void study(){ System.out.println("学生在学习"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class ReflectDemo1 { public static void main(String[] args) throws ClassNotFoundException { //1.Class类中的静态方法forName("全类名") //全类名:包名 + 类名 Class clazz = Class.forName("com.itheima.myreflect2.Student"); System.out.println(clazz); //2.通过class属性来获取 Class clazz2 = Student.class; System.out.println(clazz2); //3.利用对象的getClass方法来获取class对象 //getClass方法是定义在Object类中. Student s = new Student(); Class clazz3 = s.getClass(); System.out.println(clazz3); System.out.println(clazz == clazz2); System.out.println(clazz2 == clazz3); } }

2.3反射获取构造方法并使用

2.3.1Class类获取构造方法对象的方法

方法介绍

方法名说明Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组Constructor getConstructor(Class<?>… parameterTypes)返回单个公共构造方法对象Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个构造方法对象

示例代码

public class Student { private String name; private int age; //私有的有参构造方法 private Student(String name) { System.out.println("name的值为:" + name); System.out.println("private...Student...有参构造方法"); } //公共的无参构造方法 public Student() { System.out.println("public...Student...无参构造方法"); } //公共的有参构造方法 public Student(String name, int age) { System.out.println("name的值为:" + name + "age的值为:" + age); System.out.println("public...Student...有参构造方法"); } } public class ReflectDemo1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { //method1(); //method2(); //method3(); //method4(); } private static void method4() throws ClassNotFoundException, NoSuchMethodException { // Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): // 返回单个构造方法对象 //1.获取Class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); Constructor constructor = clazz.getDeclaredConstructor(String.class); System.out.println(constructor); } private static void method3() throws ClassNotFoundException, NoSuchMethodException { // Constructor<T> getConstructor(Class<?>... parameterTypes): // 返回单个公共构造方法对象 //1.获取Class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); //小括号中,一定要跟构造方法的形参保持一致. Constructor constructor1 = clazz.getConstructor(); System.out.println(constructor1); Constructor constructor2 = clazz.getConstructor(String.class, int.class); System.out.println(constructor2); //因为Student类中,没有只有一个int的构造,所以这里会报错. Constructor constructor3 = clazz.getConstructor(int.class); System.out.println(constructor3); } private static void method2() throws ClassNotFoundException { // Constructor<?>[] getDeclaredConstructors(): // 返回所有构造方法对象的数组 //1.获取Class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); Constructor[] constructors = clazz.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } } private static void method1() throws ClassNotFoundException { // Constructor<?>[] getConstructors(): // 返回所有公共构造方法对象的数组 //1.获取Class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); Constructor[] constructors = clazz.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } } }

2.3.2Constructor类用于创建对象的方法

方法介绍

方法名说明T newInstance(Object…initargs)根据指定的构造方法创建对象setAccessible(boolean flag)设置为true,表示取消访问检查

示例代码

// Student类同上一个示例,这里就不在重复提供了 public class ReflectDemo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //T newInstance(Object... initargs):根据指定的构造方法创建对象 //method1(); //method2(); //method3(); //method4(); } private static void method4() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { //获取一个私有的构造方法并创建对象 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); //2.获取一个私有化的构造方法. Constructor constructor = clazz.getDeclaredConstructor(String.class); //被private修饰的成员,不能直接使用的 //如果用反射强行获取并使用,需要临时取消访问检查 constructor.setAccessible(true); //3.直接创建对象 Student student = (Student) constructor.newInstance("zhangsan"); System.out.println(student); } private static void method3() throws ClassNotFoundException, InstantiationException, IllegalAccessException { //简写格式 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); //2.在Class类中,有一个newInstance方法,可以利用空参直接创建一个对象 Student student = (Student) clazz.newInstance();//这个方法现在已经过时了,了解一下 System.out.println(student); } private static void method2() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); //2.获取构造方法对象 Constructor constructor = clazz.getConstructor(); //3.利用空参来创建Student的对象 Student student = (Student) constructor.newInstance(); System.out.println(student); } private static void method1() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect3.Student"); //2.获取构造方法对象 Constructor constructor = clazz.getConstructor(String.class, int.class); //3.利用newInstance创建Student的对象 Student student = (Student) constructor.newInstance("zhangsan", 23); System.out.println(student); } }

2.3.3小结

获取class对象

三种方式: Class.forName(“全类名”), 类名.class, 对象名.getClass()

获取里面的构造方法对象

getConstructor (Class<?>… parameterTypes) getDeclaredConstructor (Class<?>… parameterTypes)

如果是public的,直接创建对象

newInstance(Object… initargs)

如果是非public的,需要临时取消检查,然后再创建对象

setAccessible(boolean) 暴力反射

2.4反射获取成员变量并使用

2.4.1Class类获取成员变量对象的方法

方法分类

方法名说明Field[] getFields()返回所有公共成员变量对象的数组Field[] getDeclaredFields()返回所有成员变量对象的数组Field getField(String name)返回单个公共成员变量对象Field getDeclaredField(String name)返回单个成员变量对象

示例代码

public class Student { public String name; public int age; public String gender; private int money = 300; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", money=" + money + '}'; } } public class ReflectDemo1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { // method1(); //method2(); //method3(); //method4(); } private static void method4() throws ClassNotFoundException, NoSuchFieldException { // Field getDeclaredField(String name):返回单个成员变量对象 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect4.Student"); //2.获取money成员变量 Field field = clazz.getDeclaredField("money"); //3.打印一下 System.out.println(field); } private static void method3() throws ClassNotFoundException, NoSuchFieldException { // Field getField(String name):返回单个公共成员变量对象 //想要获取的成员变量必须是真实存在的 //且必须是public修饰的. //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect4.Student"); //2.获取name这个成员变量 //Field field = clazz.getField("name"); //Field field = clazz.getField("name1"); Field field = clazz.getField("money"); //3.打印一下 System.out.println(field); } private static void method2() throws ClassNotFoundException { // Field[] getDeclaredFields():返回所有成员变量对象的数组 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect4.Student"); //2.获取所有的Field对象 Field[] fields = clazz.getDeclaredFields(); //3.遍历 for (Field field : fields) { System.out.println(field); } } private static void method1() throws ClassNotFoundException { // Field[] getFields():返回所有公共成员变量对象的数组 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect4.Student"); //2.获取Field对象. Field[] fields = clazz.getFields(); //3.遍历 for (Field field : fields) { System.out.println(field); } } }

2.4.2Field类用于给成员变量赋值的方法

方法介绍

方法名说明void set(Object obj, Object value)赋值Object get(Object obj)获取值

示例代码

// Student类同上一个示例,这里就不在重复提供了 public class ReflectDemo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException { // Object get(Object obj) 返回由该 Field表示的字段在指定对象上的值。 //method1(); //method2(); } private static void method2() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException { //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect4.Student"); //2.获取成员变量Field的对象 Field field = clazz.getDeclaredField("money"); //3.取消一下访问检查 field.setAccessible(true); //4.调用get方法来获取值 //4.1创建一个对象 Student student = (Student) clazz.newInstance(); //4.2获取指定对象的money的值 Object o = field.get(student); //5.打印一下 System.out.println(o); } private static void method1() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException { // void set(Object obj, Object value):给obj对象的成员变量赋值为value //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect4.Student"); //2.获取name这个Field对象 Field field = clazz.getField("name"); //3.利用set方法进行赋值. //3.1先创建一个Student对象 Student student = (Student) clazz.newInstance(); //3.2有了对象才可以给指定对象进行赋值 field.set(student,"zhangsan"); System.out.println(student); } }

2.5反射获取成员方法并使用

Class类获取成员方法对象的方法

方法分类

方法名说明Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的Method[] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的Method getMethod(String name, Class<?>… parameterTypes)返回单个公共成员方法对象Method getDeclaredMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象

示例代码

public class Student { //私有的,无参无返回值 private void show() { System.out.println("私有的show方法,无参无返回值"); } //公共的,无参无返回值 public void function1() { System.out.println("function1方法,无参无返回值"); } //公共的,有参无返回值 public void function2(String name) { System.out.println("function2方法,有参无返回值,参数为" + name); } //公共的,无参有返回值 public String function3() { System.out.println("function3方法,无参有返回值"); return "aaa"; } //公共的,有参有返回值 public String function4(String name) { System.out.println("function4方法,有参有返回值,参数为" + name); return "aaa"; } } public class ReflectDemo1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { //method1(); //method2(); //method3(); //method4(); //method5(); } private static void method5() throws ClassNotFoundException, NoSuchMethodException { // Method getDeclaredMethod(String name, Class<?>... parameterTypes): // 返回单个成员方法对象 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect5.Student"); //2.获取一个成员方法show Method method = clazz.getDeclaredMethod("show"); //3.打印一下 System.out.println(method); } private static void method4() throws ClassNotFoundException, NoSuchMethodException { //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect5.Student"); //2.获取一个有形参的方法function2 Method method = clazz.getMethod("function2", String.class); //3.打印一下 System.out.println(method); } private static void method3() throws ClassNotFoundException, NoSuchMethodException { // Method getMethod(String name, Class<?>... parameterTypes) : // 返回单个公共成员方法对象 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect5.Student"); //2.获取成员方法function1 Method method1 = clazz.getMethod("function1"); //3.打印一下 System.out.println(method1); } private static void method2() throws ClassNotFoundException { // Method[] getDeclaredMethods(): // 返回所有成员方法对象的数组,不包括继承的 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect5.Student"); //2.获取Method对象 Method[] methods = clazz.getDeclaredMethods(); //3.遍历一下数组 for (Method method : methods) { System.out.println(method); } } private static void method1() throws ClassNotFoundException { // Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的 //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect5.Student"); //2.获取成员方法对象 Method[] methods = clazz.getMethods(); //3.遍历 for (Method method : methods) { System.out.println(method); } } }

Method类用于执行方法的方法

方法介绍

方法名说明Object invoke(Object obj, Object… args)运行方法

参数一: 用obj对象调用该方法

参数二: 调用方法的传递的参数(如果没有就不写)

返回值: 方法的返回值(如果没有就不写)

示例代码

public class ReflectDemo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { // Object invoke(Object obj, Object... args):运行方法 // 参数一:用obj对象调用该方法 // 参数二:调用方法的传递的参数(如果没有就不写) // 返回值:方法的返回值(如果没有就不写) //1.获取class对象 Class clazz = Class.forName("com.itheima.myreflect5.Student"); //2.获取里面的Method对象 function4 Method method = clazz.getMethod("function4", String.class); //3.运行function4方法就可以了 //3.1创建一个Student对象,当做方法的调用者 Student student = (Student) clazz.newInstance(); //3.2运行方法 Object result = method.invoke(student, "zhangsan"); //4.打印一下返回值 System.out.println(result); } }

枚举

概述

为了间接的表示一些固定的值,Java就给我们提供了枚举 是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内

定义格式

格式

public enum s { 枚举项1,枚举项2,枚举项3; } 注意: 定义枚举类要用关键字enum

示例代码

// 定义一个枚举类,用来表示春,夏,秋,冬这四个固定值 public enum Season { SPRING,SUMMER,AUTUMN,WINTER; }

枚举的特点

特点

所有枚举类都是Enum的子类

我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项

每一个枚举项其实就是该枚举的一个对象

枚举也是一个类,也可以去定义成员变量

枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略

枚举类可以有构造器,但必须是private的,它默认的也是private的。

枚举项的用法比较特殊:枚举("");

枚举类也可以有抽象方法,但是枚举项必须重写该方法

示例代码

public enum Season { SPRING("春"){ //如果枚举类中有抽象方法 //那么在枚举项中必须要全部重写 @Override public void show() { System.out.println(this.name); } }, SUMMER("夏"){ @Override public void show() { System.out.println(this.name); } }, AUTUMN("秋"){ @Override public void show() { System.out.println(this.name); } }, WINTER("冬"){ @Override public void show() { System.out.println(this.name); } }; public String name; //空参构造 //private Season(){} //有参构造 private Season(String name){ this.name = name; } //抽象方法 public abstract void show(); } public class EnumDemo { public static void main(String[] args) { /* 1.所有枚举类都是Enum的子类 2.我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项 3.每一个枚举项其实就是该枚举的一个对象 4.枚举也是一个类,也可以去定义成员变量 5.枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的, 但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略 6.枚举类可以有构造器,但必须是private的,它默认的也是private的。 枚举项的用法比较特殊:枚举(""); 7.枚举类也可以有抽象方法,但是枚举项必须重写该方法 */ //第二个特点的演示 //我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项 System.out.println(Season.SPRING); System.out.println(Season.SUMMER); System.out.println(Season.AUTUMN); System.out.println(Season.WINTER); //第三个特点的演示 //每一个枚举项其实就是该枚举的一个对象 Season spring = Season.SPRING; } }

枚举的方法

方法介绍

方法名说明String name()获取枚举项的名称int ordinal()返回枚举项在枚举类中的索引值int compareTo(E o)比较两个枚举项,返回的是索引值的差值String toString()返回枚举常量的名称static T valueOf(Class type,String name)获取指定枚举类中的指定名称的枚举值values()获得所有的枚举项

示例代码

public enum Season { SPRING,SUMMER,AUTUMN,WINTER; } public class EnumDemo { public static void main(String[] args) { // String name() 获取枚举项的名称 String name = Season.SPRING.name(); System.out.println(name); System.out.println("-----------------------------"); // int ordinal() 返回枚举项在枚举类中的索引值 int index1 = Season.SPRING.ordinal(); int index2 = Season.SUMMER.ordinal(); int index3 = Season.AUTUMN.ordinal(); int index4 = Season.WINTER.ordinal(); System.out.println(index1); System.out.println(index2); System.out.println(index3); System.out.println(index4); System.out.println("-----------------------------"); // int compareTo(E o) 比较两个枚举项,返回的是索引值的差值 int result = Season.SPRING.compareTo(Season.WINTER); System.out.println(result);//-3 System.out.println("-----------------------------"); // String toString() 返回枚举常量的名称 String s = Season.SPRING.toString(); System.out.println(s); System.out.println("-----------------------------"); // static <T> T valueOf(Class<T> type,String name) // 获取指定枚举类中的指定名称的枚举值 Season spring = Enum.valueOf(Season.class, "SPRING"); System.out.println(spring); System.out.println(Season.SPRING == spring); System.out.println("-----------------------------"); // values() 获得所有的枚举项 Season[] values = Season.values(); for (Season value : values) { System.out.println(value); } } }

注解

概述

概述

对我们的程序进行标注和解释

注解和注释的区别

注释: 给程序员看的注解: 给编译器看的

使用注解进行配置配置的优势

代码更加简洁,方便

自定义注解

格式

public @interface 注解名称 {

​ public 属性类型 属性名() default 默认值 ;

}

属性类型

基本数据类型StringClass注解枚举以上类型的一维数组

代码演示

public @interface Anno2 { } public enum Season { SPRING,SUMMER,AUTUMN,WINTER; } public @interface Anno1 { //定义一个基本类型的属性 int a () default 23; //定义一个String类型的属性 public String name() default "itheima"; //定义一个Class类型的属性 public Class clazz() default Anno2.class; //定义一个注解类型的属性 public Anno2 anno() default @Anno2; //定义一个枚举类型的属性 public Season season() default Season.SPRING; //以上类型的一维数组 //int数组 public int[] arr() default {1,2,3,4,5}; //枚举数组 public Season[] seasons() default {Season.SPRING,Season.SUMMER}; //value。后期我们在使用注解的时候,如果我们只需要给注解的value属性赋值。 //那么value就可以省略 public String value(); } //在使用注解的时候如果注解里面的属性没有指定默认值。 //那么我们就需要手动给出注解属性的设置值。 //@Anno1(name = "itheima") @Anno1("abc") public class AnnoDemo { }

注意

如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可

自定义注解案例

需求

自定义一个注解@Test,用于指定类的方法上,如果某一个类的方法上使用了该注解,就执行该方法

实现步骤

自定义一个注解Test,并在类中的某几个方法上加上注解在测试类中,获取注解所在的类的Class对象获取类中所有的方法对象遍历每一个方法对象,判断是否有对应的注解

代码实现

//表示Test这个注解的存活时间 @Retention(value = RetentionPolicy.RUNTIME) public @interface Test { } public class UseTest { //没有使用Test注解 public void show(){ System.out.println("UseTest....show...."); } //使用Test注解 @Test public void method(){ System.out.println("UseTest....method...."); } //没有使用Test注解 @Test public void function(){ System.out.println("UseTest....function...."); } } public class AnnoDemo { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException { //1.通过反射获取UseTest类的字节码文件对象 Class clazz = Class.forName("com.itheima.myanno3.UseTest"); //创建对象 UseTest useTest = (UseTest) clazz.newInstance(); //2.通过反射获取这个类里面所有的方法对象 Method[] methods = clazz.getDeclaredMethods(); //3.遍历数组,得到每一个方法对象 for (Method method : methods) { //method依次表示每一个方法对象。 //isAnnotationPresent(Class<? extends Annotation> annotationClass) //判断当前方法上是否有指定的注解。 //参数:注解的字节码文件对象 //返回值:布尔结果。 true 存在 false 不存在 if(method.isAnnotationPresent(Test.class)){ method.invoke(useTest); } } } }

元注解

概述

元注解就是描述注解的注解

元注解介绍

元注解名说明@Target指定了注解能在哪里使用@Retention可以理解为保留时间(生命周期)@Inherited表示修饰的自定义注解可以被子类继承@Documented表示该自定义注解,会出现在API文档里面。

示例代码

@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) //指定注解使用的位置(成员变量,类,方法) @Retention(RetentionPolicy.RUNTIME) //指定该注解的存活时间 //@Inherited //指定该注解可以被继承 public @interface Anno { } @Anno public class Person { } public class Student extends Person { public void show(){ System.out.println("student.......show.........."); } } public class StudentDemo { public static void main(String[] args) throws ClassNotFoundException { //获取到Student类的字节码文件对象 Class clazz = Class.forName("com.itheima.myanno4.Student"); //获取注解。 boolean result = clazz.isAnnotationPresent(Anno.class); System.out.println(result); } }
最新回复(0)