反射
17.反射
17.1 什么是类对象
- 类的对象:基于某个类new出来的对象,也称为实例对象;
- 类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)
public class TestClassObject {
public static void main(String[] args) {
Student s = new Student();//类的对象,基于模板生成的
System.out.println(s.getClass().toString());
Class c = s.getClass();//类对象,是类的对象的模板
System.out.println(c.toString());
}
}
class Student{
String name;
int age;
String sex;
public Student() {
super();
}
public Student(String name) {
super();
this.name = name;
}
public Student(int age) {
super();
this.age = age;
}
public void study() {}
public void exam() {}
public void work() {}
}
17.2 获取类对象的方法
- 通过类的对象,获取类对象;
Student s = new Student();
Class c = s.getClass(); - 通过类名获取类对象:
Class c = 类名.class; - 通过静态方法获取类对象:
Class c = Class.forName(“包名.类名”);
public class TestGetClassObject {
public static void main(String[] args) throws ClassNotFoundException {
//1.通过类的对象,获取Class对象
Person p = new Person();//类的对象
Class c = p.getClass();//类对象(Class对象,保存了Person.class 这个文件中类的所有信息)
System.out.println(c.getName());
//2.通过类名获取Class对象
Class c2 = Person.class;
System.out.println(c2.getName());
//3.通过Class的静态方法获取Class对象
Class c3 = Class.forName("com.qf.Day34.Person");
System.out.println(c3.getName());
}
//该方法返回一个类对象(Class对象)
public static Class getClassObject(String className) {
Class c = null;
try {
c = Class.forName(className);
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
return c;
}
}
class Person{
}
输出结果:
com.qf.Day34.Person
com.qf.Day34.Person
com.qf.Day34.Person
17.3 类对象的常用方法
public String getName()
public Package getPackage()
public Class<? super T> getSuperclass()
public Class<?>[] getInterfaces()
public Field[] getFields()
public Method[] getMethods()
public Constructor<?>[] getConstructors()
public T newInstance()
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestClassMethods {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//1.获取类对象
Class c = Class.forName("com.qf.Day34.Student2");
System.out.println(c.getName());
System.out.println("---Package---");
//2.获取指定类对象的包
Package pack = c.getPackage();
System.out.println(pack.getName());
System.out.println();
System.out.println("---Superclass---");
//3.获取父类的Class对象
Class superClass = c.getSuperclass();
System.out.println(superClass.getName());
System.out.println();
System.out.println("---Interfaces---");
//4.获得接口的Class对象
Class[] interfaces = c.getInterfaces();
for (Class inter : interfaces) {
System.out.println(inter.getName());
}
System.out.println();
System.out.println("---Fields---");
//获取属性(自身+父类的公开属性)
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println();
System.out.println("---Fields---");
//获取Class对象自身的所有属性(包括私有)
Field[] fields2 = c.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field.getName());
}
System.out.println();
System.out.println("---Methods---");
//获取方法(自身+父类的所有公开方法)
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
System.out.println();
System.out.println("---Methods---");
//获取Class对象自身的所有方法(包括私有)
Method[] method2 = c.getDeclaredMethods();
for (Method method : method2) {
System.out.println(method.getName()+":"+method.getReturnType());//方法名和返回值类型
}
System.out.println();
System.out.println("---Constructors---");
Constructor[] cs = c.getConstructors();
for (Constructor constructor : cs) {
System.out.print(constructor.getName()+":");
Class[] param = constructor.getParameterTypes();//获取构造方法的形参
for (Class p : param) {
System.out.println(p.getName());
}
}
System.out.println("\n\n");
Object o = c.newInstance();
Student2 stu = (Student2)o;
System.out.println(o);
System.out.println(stu);
}
}
class Person2{
public String sex;
public double money;
public void eat() {}
public void sleep() {}
}
class Student2 extends Person2 implements Serializable , Runnable , Comparable{
public String name;
int age;
String sex;
private double score;
public Student2() {
super();
}
public Student2(String name) {
super();
this.name = name;
}
public Student2(int age) {
super();
this.age = age;
}
public void study() {}
public void exam() {}
public void work() {}
private int aaa() {
return 0;
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
输出结果:
com.qf.Day34.Student2
---Package---
com.qf.Day34
---Superclass---
com.qf.Day34.Person2
---Interfaces---
java.io.Serializable
java.lang.Runnable
java.lang.Comparable
---Fields---
name
sex
money
---Fields---
name
age
sex
score
---Methods---
run
compareTo
study
exam
work
sleep
eat
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
---Methods---
run:void
compareTo:int
study:void
aaa:int
exam:void
work:void
---Constructors---
com.qf.Day34.Student2:int
com.qf.Day34.Student2:java.lang.String
com.qf.Day34.Student2:
com.qf.Day34.Student2@3d4eac69
com.qf.Day34.Student2@3d4eac69
17.4 工厂设计模式
- 开发中有一个非常重要的原则”开闭原则“,对扩展开放、对修改关闭;
- 工厂模式主要负责对象创建的问题;
- 可通过反射进行工厂模式的设计,完成动态的对象创建;
import java.io.BufferedReader;
import java.io.FileReader;
public class TestNewInstance {
public static void main(String[] args) throws Exception {
//1.手工new对象
Teacher t = new Teacher();
t.name = "Tom";
//2.反射 通过类对象创建类的对象
Class c = Teacher.class;
Teacher t2 = (Teacher)c.newInstance();
t2.name = "Alex";
System.out.println(t2.name);
//3.通过配置文件,输入流进行创建对象
FileReader fr = new FileReader("Files/application.txt");
BufferedReader br = new BufferedReader(fr);
String className = br.readLine();
Object o = createObject(className);
System.out.println(o);
}
//创建对象
//工厂:创建对象工厂
public static Object createObject(String className) {
try {
Class c = Class.forName(className);
return c.newInstance();
}catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
class Teacher{
String name;
String sex;
Integer age;
public Teacher() {
super();
}
public Teacher(String name, String sex, Integer age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
public void study() {
System.out.println("在学习。。。");
}
public void exam() {
System.out.println("在考试。。。");
}
public void calc() {
System.out.println("在算分。。。");
}
}
输出结果:
Alex
com.qf.Day34.Teacher@7852e922
import java.lang.reflect.Method;
public class TestInvokeMethod {
public static void main(String[] args) throws Exception {
//反射 类的对象
Object o = createObject("com.qf.Day35.Student");
//类对象
Class c = o.getClass();
//name方法名 parameterTypes参数列表类型
Method m = c.getMethod("study", null);
//通过invoke方法,执行某个实例方法 参数:Object-》所需对象,args-》调用方法所需的实参
m.invoke(o, null);
//调用方法,无法调用私有方法
Method m1 = c.getMethod("study", int.class);
Object result = m1.invoke(o, 3);//接收方法返回值,如果是基本类型,则转换为包装
System.out.println(result);
// System.out.println(c.getMethod("study", int.class).invoke(o, 5));
Method m2 = c.getMethod("exam", String.class , int.class , double.class);
m2.invoke(o, "tom" , 50 , 90D);
//获得自身方法,包含私有
Method m3 = c.getDeclaredMethod("calc",null);
m3.setAccessible(true);//注意:反射是一种Java底层技术,可以取消语言检查,突破封装
m3.invoke(o, null);
}
//工厂--创建对象
public static Object createObject(String className) {
try {
Class c = Class.forName(className);
return c.newInstance();
}catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
class Student{
String name;
Integer age;
String sex;
Double socre;
public Student() {}
public Student(String name, Integer age, String sex, Double socre) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.socre = socre;
}
public void study() {
System.out.println("学习中。。。");
}
public int study(int hours) {
System.out.println("学习了"+hours+"小时");
return hours;
}
public void exam(String a , int b , double c) {
System.out.println(a+"考了"+b+"分钟,得分"+c);
}
private void calc() {
System.out.println("calc");
}
}
输出结果:
学习中。。。
学习了3小时
3
tom考了50分钟,得分90.0
calc
public class TestInvokeAnything {
public static void main(String[] args) throws Exception {
//invokeAAny()-->执行方法
//对象(Object)、方法名称(String)、形参(Class)、实参(Object)
Object o = createObject("com.qf.Day35.Student");
invokeAny(o , "exam" , new Class[] {String.class,int.class,double.class},"alex",60,99D);
invokeAny(o,"study",null,null);
invokeAny(o,"study",new Class[] {int.class},10);
}
public static void invokeAny(Object obj , String methodName ,Class[] types,Object... args) throws Exception {
//使用反射技术执行任何方法
//类对象
Class c = obj.getClass();
//获得方法的对象
Method m = c.getDeclaredMethod(methodName, types);
//执行方法
m.invoke(obj, args);
}
//工厂--创建对象
public static Object createObject(String className) {
try {
Class c = Class.forName(className);
return c.newInstance();
}catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
输出结果:
alex考了60分钟,得分99.0
学习中。。。
学习了10小时
17.5 单例模式
17.5.1 单例模式1
- 单例(Singlethon):只允许创建一个该类的对象;
- 方式1:饿汉式(类加载是创建,天生线程安全)
17.5.2 单例模式2
- 方式2:懒汉式(使用时创建,线程不安全,加同步)
17.5.3 单例模式3
- 方式3:懒汉式(使用时创建,线程安全)
/*
* 单例模式,一个类只能创建一个对象
* */
public class TestSingleton {
public static void main(String[] args) {
Singleton1 s1 = Singleton1.getInstance();
System.out.println(s1 );
Singleton2 s2 = Singleton2.getInstance();
Singleton2 s3 = Singleton2.getInstance();
Singleton2.instance = null;
Singleton2 s4 = Singleton2.getInstance();
System.out.println(s2 );
System.out.println(s3 );
System.out.println(s4 );//线程不安全,可能会创建不同对象
Singleton3 s5 = Singleton3.getInstance();
Singleton3 s6 = Singleton3.getInstance();
System.out.println(s5);
System.out.println(s6);
}
}
//饿汉式:天生线程安全(无锁),类加载时创建(不用的时候也被迫创建了,占用资源)
class Singleton1{
private static final Singleton1 instance = new Singleton1();
private Singleton1() {}
public static Singleton1 getInstance() {
return instance;
}
}
//懒汉式:使用时创建,天生线程不安全(需要加同步锁),效率低
class Singleton2{
static Singleton2 instance = null;
private Singleton2() {}
public static Singleton2 getInstance() {
if(instance == null) {
instance = new Singleton2();
}
return instance;
}
}
//懒汉式:使用时创建,天生线程安全
class Singleton3{
private Singleton3() {}
private static class Holder{
static final Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance() {
return Holder.instance;
}
}
输出结果:
com.qf.Day35.Singleton1@7852e922
com.qf.Day35.Singleton2@4e25154f
com.qf.Day35.Singleton2@4e25154f
com.qf.Day35.Singleton2@70dea4e
com.qf.Day35.Singleton3@5c647e05
com.qf.Day35.Singleton3@5c647e05
17.6 总结
-
类对象:
Class对象,封装了一个类的所有信息;程序运行中,可通过Class对象获取类的信息; -
获取类对象的三种方式:
Class c = 对象.geiClass();
Class c = 类名.class;
Class c = Class.forName(“包名.类名”); -
工厂模式:
主要用于创建对象,通过反射进行工厂模式的设计,完成动态的对象创建; -
单例模式:
Singleton,只允许创建一个该类的对象;