17、反射
1、什么是类对象
类的对象:
基于某个类new 出来的对象,也称为实例对象。
类对象:
类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)

2、获取类对象
通过类的对象,获取类对象
Student s = new Student();
Class c = s.getClass();
通过类名获取类对象
Class c = 类名.class;
通过静态方法获取类对象
Class c=Class.forName("包名.类名");
3、常用方法
3.1、获取该类的名称
public String getName()
3.2、获取该类的存放路径
public Package getPackage()
3.3、获取父类名称
public Class<? super T> getSuperclass()
3.4、获取该类实现的所有接口
public Class<?>[] getlnterfaces()
3.5、获取所有权限为 public 的成员变量
public Field[] getFields()
3.6、获取所有权限为 public 的方法
public Method[] getMethods()
3.7、获取所有权限为 public 的构造方法
public Constructor<?>[] getConstructors()
3.8、用来创建新的对象
public T newlnstance()
/** * Person类 */ public class Person implements Serializable,Cloneable{ //姓名 private String name; //年龄 private int age; // 性别 public int sex; public Person() { System.out.println("无参构造执行了..."); } public Person(String name, int age) { super(); this.name = name; this.age = age; System.out.println("带参构造方法执行了..."); } //吃 public void eat() { System.out.println(name+"正在吃东西......"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } //带参的方法 public void eat(String food) { System.out.println(name+"开始吃...."+food); } //私有的方法 private void privateMethod() { System.out.println("这是一个私有方法"); } //静态方法 public static void staticMethod() { System.out.println("这是一个静态方法"); } }
//-verbose:class 显示类的加载过程 public class TestPerson { public static void main(String[] args) throws Exception { // Person zhangsan=new Person(); // zhangsan.name="张三"; // zhangsan.eat(); //getClazz(); reflectOpe1(); //reflectOpe2(); //reflectOpe3(); // Properties properties=new Properties(); // properties.setProperty("name","zhangsan"); // System.out.println(properties.toString()); // invokeAny(properties, "setProperty", new Class[] {String.class, String.class}, "username","张三"); // System.out.println(properties.toString()); // reflectOpe4(); } //获取类对象的三种方式 public static void getClazz() throws Exception { //1使用对象获取类对象 Person zhangsan=new Person(); Class<?> class1=zhangsan.getClass(); System.out.println(class1.hashCode()); //2使用类名.class属性 Class<?> class2=Person.class; System.out.println(class2.hashCode()); //3使用Class的静态方法[推荐使用] Class<?> class3=Class.forName("com.qf.chap17_1.Person"); System.out.println(class3.hashCode()); } //1 使用反射获取类的名字、包名、父类、接口 public static void reflectOpe1() throws Exception { //(1)获取类对象 Person Class<?> class1=Class.forName("com.qf.chap17_1.Person"); //getName(); // com.qf.chap17_1.Person System.out.println(class1.getName()); //getPackage(); // com.qf.chap17_1 System.out.println(class1.getPackage().getName()); //getSuperClass(); // java.lang.Object System.out.println(class1.getSuperclass().getName()); //getInterfaces(); // [interface java.io.Serializable, interface java.lang.Cloneable] Class<?>[] classes=class1.getInterfaces(); System.out.println(Arrays.toString(classes)); // getFields Field[] fields = class1.getFields(); System.out.println("getFields==="+Arrays.toString(fields)); // getMethods Method[] methods = class1.getMethods(); System.out.println("methods==="+Arrays.toString(methods)); // Person System.out.println(class1.getSimpleName()); // com.qf.chap17_1.Person System.out.println(class1.getTypeName()); } //2使用反射获取类的构造方法,创建对象 public static void reflectOpe2() throws Exception{ //(1)获取类的类对象 Class<?> class1=Class.forName("com.qf.chap17_1.Person"); //(2)获取类的构造方法 Constructor // Constructor<?>[] cons=class1.getConstructors(); // for (Constructor<?> con : cons) { // System.out.println(con.toString()); // } //(3)获取类中无参构造 Constructor<?> con=class1.getConstructor(); Person zhangsan=(Person)con.newInstance(); Person lisi=(Person)con.newInstance(); System.out.println(zhangsan.toString()); System.out.println(lisi.toString()); //简便方法:类对象.newInstance(); Person wangwu=(Person)class1.newInstance(); System.out.println(wangwu.toString()); //(4)获取类中带参构造方法 Constructor<?> con2=class1.getConstructor(String.class,int.class); Person xiaoli=(Person)con2.newInstance("晓丽",20); System.out.println(xiaoli.toString()); } //3使用反射获取类中的方法,并调用方法 public static void reflectOpe3() throws Exception{ //(1)获取类对象 Class<?> class1=Class.forName("com.qf.chap17_1.Person"); //(2)获取方法 Method对象 //2.1getMethods() 获取公开的方法,包括从父类继承的方法 //Method[] methods=class1.getMethods(); //2.2getDeclaredMethods() 获取类中的所有方法,包括私有、默认、保护的 、不包含继承的方法 // Method[] methods=class1.getDeclaredMethods(); // for (Method method : methods) { // System.out.println(method.toString()); // } //(3)获取单个方法 //3.1eat Method eatMethod=class1.getMethod("eat"); //调用方法 //正常调用方法 Person zhangsan=new Person(); zhangsan.eat(); Person zhangsan=(Person)class1.newInstance(); eatMethod.invoke(zhangsan);//zhangsan.eat(); System.out.println("------------------"); //3.2toString Method toStringMethod=class1.getMethod("toString"); Object result=toStringMethod.invoke(zhangsan); System.out.println(result); System.out.println("-------------------"); //3.3带参的eat Method eatMethod2=class1.getMethod("eat", String.class); eatMethod2.invoke(zhangsan, "鸡腿"); //3.4获取私有方法 Method privateMethod=class1.getDeclaredMethod("privateMethod"); //设置访问权限无效 privateMethod.setAccessible(true); privateMethod.invoke(zhangsan); //3.4获取静态方法 Method staticMethod=class1.getMethod("staticMethod"); //正常调用 Person.staticMethod staticMethod.invoke(null); } //4使用反射实现一个可以调用任何对象方法的通用方法 public static Object invokeAny(Object obj,String methodName,Class<?>[] types,Object...args) throws Exception { //1获取类对象 Class<?> class1=obj.getClass(); //2获取方法 Method method=class1.getMethod(methodName, types); //3调用 return method.invoke(obj, args); } //5使用反射获取类中的属性 public static void reflectOpe4() throws Exception{ //(1)获取类对象 Class<?> class1=Class.forName("com.qf.chap17_1.Person"); //(2)获取属性(字段) 公开的字段,父类继承的字段 //Field[] fields=class1.getFields(); //getDeclaredFields()获取所有的属性,包括私有,默认 ,包含, // Field[] fields=class1.getDeclaredFields(); // System.out.println(fields.length); // for (Field field : fields) { // System.out.println(field.toString()); // } //(3)获取name属性 Field namefield=class1.getDeclaredField("name"); namefield.setAccessible(true); //(4)赋值 获取值 正常调用 Person zhangsan=new Person(); zhangsan.name="张三"; Person zhangsan=(Person)class1.newInstance(); namefield.set(zhangsan, "张三"); //zhangsan.name="张三"; //(5) 获取值 System.out.println(namefield.get(zhangsan));// zhangsan.name } }
3、设计模式
什么是设计模式:
一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。·可以简单理解为特定问题的固定解决方法。
好处:
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、重用性。
4、工厂设计模式
开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭。
工厂模式主要负责对象创建的问题。
可通过反射进行工厂模式的设计,完成动态的对象创建。
1、父类产品
/** * 父类产品 * */ public interface Usb { void service(); }
2、风扇
/** * 风扇 */ public class Fan implements Usb{ @Override public void service() { System.out.println("风扇开始工作了..."); } }
3、键盘
/** * 键盘 */ public class KeyBoard implements Usb{ @Override public void service() { System.out.println("键盘开始工作了..."); } }
4、鼠标
/** * 鼠标 */ public class Mouse implements Usb{ @Override public void service() { System.out.println("鼠标开始工作了....."); } }
5、U盘
/** * U盘 */ public class Upan implements Usb{ @Override public void service() { System.out.println("U盘开始工作了..."); } }
6、工厂类
/** * 工厂类 */ public class UsbFactory { public static Usb createUsb(String type) {//类型的全名称 com.qf. Usb usb=null; Class<?> class1=null; try { class1 = Class.forName(type); usb=(Usb)class1.newInstance(); } catch (Exception e) { System.out.println(e.getMessage()); } return usb; } }
7、客户程序
/** * 客户程序 */ public class Demo { public static void main(String[] args) throws Exception{ System.out.println("=========请选择 1 鼠标 2风扇 3 u盘==========="); Scanner input=new Scanner(System.in); String choice=input.next(); //1 = com.qf.chap17_2.Mouse //2 = com.qf.chap17_2.Fan //3 = com.qf.chap17_2.Upan //4 = com.qf.chap17_2.KeyBoard Properties properties=new Properties(); FileInputStream fis=new FileInputStream("src\\usb.properties"); properties.load(fis); fis.close(); Usb usb=UsbFactory.createUsb(properties.getProperty(choice)); if(usb!=null) { System.out.println("购买成功"); usb.service(); }else { System.out.println("购买失败,您要购买的产品不存在"); } } }
5、单例模式
单例(Singleton):只允许创建一个该类的对象。
方式1: 饿汉式(类加载时创建,天生线程安全)
/** * 饿汉式单例 * (1)首先创建一个常量 * (2)构造方法改成私有的,类外部不能创建对象 * (3)通过一个公开的方法,返回这个对象 * * 优点:线程安全,缺点:声明周期太长,浪费空间 * */ public class SingleTon { private static final SingleTon instance=new SingleTon(); private SingleTon() {} public static SingleTon getInstance() { return instance; } }
方式2: 懒汉式(使用时创建,线程不安全,加同步)
/** * 懒汉式单例 * (1)首先创建一个对象,赋值为null * (2)构造方法改成私有的,类外部不能创建对象 * (3)通过一个公开的方法,返回这个对象 * * 优点:声明周期短,节省空间 缺点:有线程安全问题 * */ public class SingleTon2 { // 创建对象 private static SingleTon2 instance = null; // 私有化构造方法 private SingleTon2() { } // 静态方法 public static SingleTon2 getInstance() { if(instance==null) {//提高执行效率 synchronized (SingleTon2.class) { if (instance == null) { instance = new SingleTon2(); } } } return instance; } }
方式3: 懒汉式(使用时创建,线程安全)
/** * 单例第三种写法:静态内部类写法 * */ public class SingleTon3 { private SingleTon3() {} private static class Holder{ static SingleTon3 instance=new SingleTon3(); } public static SingleTon3 getInstance() { return Holder.instance; } }
6、枚举
1、什么是枚举:
枚举是一个引用类型,枚举是一个规定了取值范围的数据类型。
2、枚举变量不能使用其他的数据,只能使用枚举中常量赋值,提高程序安全性。
3、定义枚举使用enum关键字。
4、枚举的本质:
枚举是一个终止类,并继承Enum抽象类。
枚举中常量是当前类型的静态常量。
/** * 性别枚举 * 注意 * (1)枚举中必须要包含枚举常量,也可以包含属性、方法、私有构造方法 * (2)枚举常量必须在前面,多个常量之间使用逗号隔开,最后分号可写可不写 * */ public enum Gender { MALE,FEMALE; }
/** * 季节枚举 * */ public enum Season { SPRING,SUMMER,AUTUMN,WINTER; }
public class TestGender { public static void main(String[] args) { Gender gender=Gender.MALE; System.out.println(gender.toString()); Season season=Season.SPRING; System.out.println(season.toString()); } }
7、注解
什么是注解:
注解(Annotation)是代码里的特殊标记,程序可以读取注解,一般用于替代配置文件。
开发人员可以通过注解告诉类如何运行。
在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
常见注解:@Override、@Deprecated
定义注解使用@interface关键字,注解中只能包含属性。
注解属性类型:
1、String类型
2、基本数据类型
3、Class类型
4、枚举类型
5、注解类型
6、以上类型的一维数组
/** * 创建注解类型 @interface * */ public @interface MyAnnotation { //属性(类似方法) String name() default "张三"; int age() default 20; }
public @interface MyAnnotation2 { //属性 //字符串类型 String value(); //基本类型 int num() default 20; //Class类型 Class<?> class1(); //枚举类型 Gender gender(); //注解类型 MyAnnotation annotation(); //ArrayList<String> list(); }
public class Person { @MyAnnotation() public void show() { } //@MyAnnotation2(value="大肉",num=25) public void eat() { } @PersonInfo(name="小岳岳",age=30,sex="男") public void show(String name,int age,String sex) { System.out.println(name+"==="+age+"===="+sex); } }
元注解:
用来描述注解的注解。
@Retention:用于指定注解可以保留的域。
RetentionPolicy.CLASS:
注解记录在class文件中,运行Java程序时,JVM不会保留,此为默认值。
RetentionPolicy.RUNTIME:
注解记录在class文件中,运行Java程序时,JVM会保留,程序可以通过反射获取该注释。
RetentionPolicy.SOURCE:
编译时直接丢弃这种策略的注释。
@Target:
指定注解用于修饰类的哪个成员。
@Retention(value=RetentionPolicy.RUNTIME) @Target(value= {ElementType.METHOD}) public @interface PersonInfo { String name(); int age(); String sex(); }
public class Demo { public static void main(String[] args) throws Exception{ //(1)获取类对象 Class<?> class1=Class.forName("com.qf.chap17_5.Person"); //(2)获取方法 Method method=class1.getMethod("show", String.class,int.class,String.class); //(3)获取方法上面的注解信息 personInfo=null PersonInfo personInfo=method.getAnnotation(PersonInfo.class); //(4)打印注解信息 System.out.println(personInfo.name()); System.out.println(personInfo.age()); System.out.println(personInfo.sex()); //(5)调用方法 Person yueyue=(Person)class1.newInstance(); method.invoke(yueyue, personInfo.name(),personInfo.age(),personInfo.sex()); } }
8、总结
类对象:
Class对象,封装了一个类的所有信息;程序运行中,可通过Class对象获取类的信息。
获取类对象的三种方式:
Class c=对象.getClass();
Class c =类名.class;
Class c=Class.forName(“包名.类名”);
工厂模式:
主要用于创建对象,通过反射进行工厂模式的设计,完成动态的对象创建。
单例模式:
Singleton,只允许创建一个该类的对象。
枚举类型、注解类型

浙公网安备 33010602011771号