反射(Reflect)
1.反射:把Java类中的各种成分映射成单独的Java对象进行操作。
2.类的对象:基于某个类new出来的对象,也称为实例对象。
3.类对象:类加载的产物,封装了一个类的所有信息(类名,父类,接口,属性,方法,构造方法)。
获取类的类对象
前两种方式依赖性太强,推荐使用第三种方式,耦合性低,比较灵活。
通过对象获取
Wife wife = new Wife("艾米莉亚",16);
Class<?> class1 = wife.getClass();
类名.class
//class是每个类都有的属性
Class<?> class2 = Student.class;
Class.forName()
//会抛异常
Class<?> class3 = Class.forName("必须是类的带包全名");
获取构造方法
获取所有构造方法
Constructor<?>[] constructors = class1.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
获取带参构造方法
Constructor<?> constructor = class1.getConstructor(String.class, int.class, String.class);
Student s1=(Student) constructor.newInstance("艾米莉亚",18,"女神");
获取无参构造方法
Constructor constructor2=class1.getConstructor();
Student s2=(Student) constructor2.newInstance();
//简写
Student s1 = (Student)class1.newInstance()
获取方法
获取所有方法
//getMethods()获取公开的所有方法,包括继承的公开方法;没有私有、默认,保护的方法
Method[] methods = class1.getMethods();
//getDeclaredMethods() 获取类中所有的方法,包含私有、默认、保护的方法。不包括继承的。
Method[] methods =class1.getDeclaredMethods();
获取单个方法
Student s1 = (Student) class1.newInstance();
//获取无参方法
Method methodShow=class1.getMethod("show");
methodShow.invoke(s1);//调用
//获取带参方法
Method methodShow2 = class1.getMethod("show", String.class);
methodShow2.invoke(s1,"上海");
//获取静态方法
Method staticMethod=class1.getMethod("staticMethod");
staticMethod.invoke(null);
//获取私有方法
Method privateMethod=class1.getDeclaredMethod("privateMethod");
//设置访问权限失效
privateMethod.setAccessible(true);
privateMethod.invoke(s1);
给属性赋值
Class<?> class1 = Class.forName("com.qf.gp2002_2.Person");
Object person = class1.newInstance();
反射赋值,不符合封装
Field name = class1.getDeclaredField("name");
Field age = class1.getDeclaredField("age");
Field gender = class1.getDeclaredField("gender");
获取set方法,麻烦,不知道方法形参属性
Method setName = class1.getMethod("setName", String.class);
Method setAge = class1.getMethod("setAge", int.class);
Method setGender = class1.getMethod("setGender", String.class);
内省(透视类的内部)
https://blog.csdn.net/qq_41033290/article/details/85834927
属性:如果类中包含了getXxx、setXxx、isXxx开头的方法,表示类中有xxx属性
//获取所有属性
// BeanInfo beanInfo = Introspector.getBeanInfo(class1);
// PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
// for (PropertyDescriptor pd : pds) {
// System.out.println(pd.getName());
// }
//给属性赋值
//name属性
PropertyDescriptor pdName=new PropertyDescriptor("name", class1);
System.out.println(pdName.getPropertyType());//获取属性类型
Method writeMethod = pdName.getWriteMethod(); //setName()方法
writeMethod.invoke(person,"铸玺");
PropertyDescriptor pdAge=new PropertyDescriptor("age", class1);
System.out.println(pdAge.getPropertyType());
Method writeMethod1 = pdAge.getWriteMethod();
writeMethod1.invoke(person,20);
PropertyDescriptor pdGender=new PropertyDescriptor("gender",class1);
System.out.println(pdGender.getPropertyType());
Method writeMethod2 = pdGender.getWriteMethod();
writeMethod2.invoke(person,"男");
System.out.println("-----------------------");
//获取属性
Method readMethod = pdName.getReadMethod();//getName
System.out.println(readMethod.invoke(person));
Method readMethod1 = pdAge.getReadMethod();//getAge
System.out.println(readMethod1.invoke(person));
Method readMethod2 = pdGender.getReadMethod();//getGender
System.out.println(readMethod2.invoke(person));
单例模式
1.要求整个程序只有一个对象。
2.步骤:
(1)私有化构造方法
(2)在类内部创建一个对象
(3)通过公开的方法返回这个对象
饿汉式
类一加载,对象就初始化。
缺点:生命周期太长,浪费空间。优点:线程安全。
public class SingleTon {
//1私有化构造方法
private SingleTon(){}
//2创建对象
private static final SingleTon instance=new SingleTon();
//3通过公开的方法,返回这个对象
public static SingleTon getInstance(){
return instance;
}
}
懒汉式
好处:生命周期短,节省空间
缺点:线程不安全,必须使用同步解决
public class SingleTon2 {
//(1)私有化构造方法
private static boolean flag=false;
private SingleTon2(){
if(flag){
throw new RuntimeException("不能反射破解");
}
}
//(2)在类内部创建一个对象
private static volatile SingleTon2 instance;
//(3)通过公开的方法,返回这个对象
public static SingleTon2 getInstance(){
//判断锁是否可用效率低
if(instance==null) {//目的:提高效率, double check双重检查
synchronized (SingleTon2.class) {
if (instance == null) {
//(1)new (2)dup (3)invokespecial (4)astore
// 1 2 3 4
// 1 2 4 3 多线程问题?
instance = new SingleTon2();
flag=true;
}
}
}
return instance;
}
}
静态内部类写法
优点:1 安全 2 生命周期短,节省空间
public class SingleTon3 {
//1私有化构造方法
private SingleTon3(){}
//2在静态内部类中创建对象
private static class Holder{
private static final SingleTon3 instance=new SingleTon3();
}
//3通过公开方法返回这个对象
public static SingleTon3 getInstance(){
return Holder.instance;
}
}
枚举
1.枚举类:规定了取值范围的数据类型。
2.注意事项:
(1)枚举常量之间用逗号隔开,最后分号可写也可不写,如果后面有代码,必须加分号
(2)枚举包含私有构造方法,属性和普通方法,必须写在常量后面。
public enum Gender {
MALE,FEMALE;
private Gender(){
}
public String value;
public void show(){
System.out.println(value);
}
}
注解
注解中:
(1)只能包含公开属性:1.基本类型,2.String类型,3.Class类型,4.枚举类型,5.注解类型,6.以及上述类型的一维数组。
(2)定义属性时,可以给默认值
(3)如果注解中使用value属性名,使用可以不用写value
public @interface MyAnnotation {
int value;
}
通过反射获取方法注解属性
@MyAnnotation(100)
public class Test{
public void show(){
Class<?> class1 = Class.forName("Test的带包全名");
class1.getMethod("show");
Annotation[] annotations = show.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
}
}