Java反射
类对象
类的对象:基于某个类new出来的对象,也称为实例对象
类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)
每一个类加载到内存之后,都对应一个Class对象,每个类有且只有一个
JVM参数:-verbose:class显示类的加载过程
获取类对象
- 通过类的对象,获取类对象
- Student s=new Student();
- Class<?> c=s.getClass();
- 通过类名获取类对象
- Class c=类名.class;
- 通过静态方法
- Class c=Class.forName(“包名.类名");
反射常用操作
- public String getName();
- public Package getPackage()
- public Class<? super T> getSuperclass()
- public Class<?>[] getInterfaces()
- public Constructor<?>[] getConstructors()
- public T newInstance()
- public Method[] getMethods()
- public Field [] getFields() 获取属性
Person类,以下操作都用它
package net;
import java.io.Serializable;
/**
* Person类
* @author wgy
*
*/
public class Person implements Serializable,Cloneable{
//姓名
private String name;
//年龄
private int age;
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("这是一个静态方法");
}
}
一、获取类的名字、包名、父类、接口
package net;
import java.util.ArrayList;
import java.util.Arrays;
public class TestPerson {
public static void main(String[] args) throws Exception{
reflectOpen1();
}
public static void reflectOpen1() throws Exception {
Class<?> class1=Class.forName("net.Person");
System.out.println(class1.getName());
System.out.println(class1.getPackage().getName());
System.out.println(class1.getSuperclass().getName());
Class<?>[] classes= class1.getInterfaces();
System.out.println(Arrays.toString(classes));
System.out.println(class1.getSimpleName());
System.out.println(class1.getTypeName());
}
}
net.Person
net
java.lang.Object
[interface java.io.Serializable, interface java.lang.Cloneable]
Person
net.Person
二、获取类中的构造方法,创建对象
public static void reflectOpen2() throws Exception{
Class<?> class1=Class.forName("net.Person");
//获取类的构造方法
Constructor<?>[] constructors= class1.getConstructors();
for ( Constructor<?> constructor:constructors)
{
System.out.println(constructor.toString());
}
Constructor<?> constructor=class1.getConstructor();
Person zhangshan=(Person)constructor.newInstance();
System.out.println(zhangshan.toString());
//简便方法
Person person=(Person)class1.newInstance();
System.out.println(person.toString());
Constructor<?> constructor1=class1.getConstructor(String.class,int.class);
Person xiaoli=(Person)constructor1.newInstance("小李",20);
System.out.println(xiaoli.toString());
}
}
public net.Person()
public net.Person(java.lang.String,int)
无参构造执行了…
Person [name=null, age=0]
无参构造执行了…
Person [name=null, age=0]
带参构造方法执行了…
Person [name=小李, age=20]
三、使用反射获取类中的方法并调用方法
public static void reflectOpen3() throws Exception {
//获取类对象
Class<?> class1=Class.forName("net.Person");
//公开和继承的父类的方法
Method[] methods=class1.getMethods();
for (Method m :methods) {
System.out.println(m.toString());
}
System.out.println("=========");
//可获取私有方法,不包含继承的
Method[] methods1=class1.getDeclaredMethods();
for (Method m :methods1) {
System.out.println(m.toString());
}
Method method=class1.getMethod("eat");
Person person=(Person)class1.newInstance();
method.invoke(person);
Method method1=class1.getMethod("toString");
;
System.out.println( method1.invoke(person));
System.out.println("======");
Method method2=class1.getMethod("eat", String.class);
method2.invoke(person,"牛奶");
Method method3=class1.getDeclaredMethod("privateMethod");
//私有方法设置访问权限失效
method3.setAccessible(true);
method3.invoke(person);
//静态
Method method4=class1.getMethod("staticMethod");
method4.invoke(null);
}
四、使用反射实现可以调用任何对象方法的通用方法
public static Object invokeAny(Object obj,String methodName,Class<?>[] types,Object...args) throws Exception {
Class<?> c =obj.getClass();
Method method= c.getMethod(methodName,types);
return method.invoke(obj,args);
}
五、获取类中的属性
public static void reflectOpen4() throws Exception {
Class<?> class1=Class.forName("net.Persom");
Field field=class1.getField("name");
field.setAccessible(true);
Person person=class1.newInstance();
field.set(person,"张三");
System.out.println(person.toString());
}
设计模式
一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。简单理解:特定问题的固定解法
好处:使用设计模式是为了可重用代码、让代码更容易被他人理解 、保证代码可靠性、重用性。
一、工厂设计模式
工厂模式主要负责对象创建的问题。
开发中有一个非常重要的原则“开闭原则”,对扩展开放,修改关闭。
可通过反射进行工厂模式的设计,完成动态的对象创建
public class UsbFactory {
public static Usb createUsb(String type) throws Exception {
Usb usb=null;
Class<?> class1=Class.forName(type);
Usb usb1= (Usb) class1.newInstance();
return usb;
}
}
二、单例模式
只允许创建一个该类的对象
1.饿汉式:
类加载时创建,天生线程安全
public class SingleTon {
private static final SingleTon instance=new SingleTon();
private SingleTon(){}
public SingleTon getInstance(){
return instance;
}
}
多线程情况下,拿到的对象都是同一个
2.懒汉式
使用时创建,线程不安全,加同步
package Single;
public class SingleTon2 {
private static SingleTon2 singleTon2=null;
private SingleTon2(){}
public static synchronized SingleTon2 getInstance(){
if(singleTon2==null){
singleTon2=new SingleTon2();
}
return singleTon2;
}
}
多线程下,不加synchronized打印的hashCode会不一样,线程不安全,或者同步代码块也可以,其中的锁应该是类.class
为提高效率,可以在外层加一个判断
3.懒汉式(使用时创建,线程安全)
package Single;
import org.omg.CORBA.PUBLIC_MEMBER;
import sun.security.rsa.RSASignature;
public class SingleTon3 {
private SingleTon3(){
}
//不使用不会执行
private static class Holder{
static SingleTon3 singleTon3=new SingleTon3();
}
public static SingleTon3 getInstance(){
return Holder.singleTon3;
}
}
枚举
什么是枚举
引用类型,枚举是一个规定了取值范围的数据类型;
枚举遍历不能使用其他数据,只能使用枚举中常量赋值,提高程序安全性
定义使用enum关键字
要求:必须包含常量,也可以包含属性和方法,私有构造方法
枚举常量必须在前面,多个常量之间使用,隔开,最后分号,可写可不写
实际就是终止类,继承了Enum抽象类
常量是当前静态类型的常量
package Single;
/*
必须包含常量,也可以包含属性和方法,私有构造方法
枚举常量必须在前面,多个常量之间使用,隔开,最后分号,可写可不写
*/
public enum Gender {
MALE,FEMALE;
private String value;
private Gender(){
}
public void show(){};
}
注解
什么是注解
代码里的特殊标记,程序可以读取注解,一般用于替代配置文件
开发人员可以通过注解告诉类如何运行
可以通过反射技术去得到类里面的注解,以决定怎么运行类
常见注解
@Override
@Deprecated(过时)
定义注解使用@interface关键字,注解中只能包含属性
定义注解
public @interface MyAnnotation {
//属性类似方法
String name() default "张三";
int age() default 20;
}
public class Person {
@MyAnnotation(name="张三",age=20)
public void show(){
}
}
注解的属性类型
- String
- 基本数据类型
- Class类型
- 注解类型
- 以上类型的一维数组
注解的本质
就是接口
反射获取注解信息
元注解
用来描述注解的注解
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
//属性类似方法
String name() default "张三";
int age() default 20;
String sex();
}
@Target:指定注解修饰类的哪个成员
@Target(value = {ElementType.TYPE,ElementType.METHOD})//只能用在类上面,方法上面