反射
多态是不能调用子类独有的方法的,形象来说程序是不知道user是个child
如果能在运行过程中知道user是什么类型,那就能用child里面的方法了
好比通过照镜子知道自己长什么样,java中就有反射这种机制在运行中得到对象的类型等相关信息
通过反射的方式来获取整体的对象--类对象
Class<? extends User> aClass = user.getClass();//类对象
编译后的字节码文件
javap是java提供的反编译cmd命令
创建完类对象就能根据类对象获取一些信息了
package Reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class demo {
public static void main(String[] args) throws Exception{
User user = new Child();
Class<? extends User> aClass = user.getClass();//类对象
//java万物皆对象,Class对应编译后的字节码文件.class
//获取类名
System.out.println(aClass.getName());//Reflect.Child 包名.类名
System.out.println(aClass.getSimpleName());//类名 Child
System.out.println(aClass.getPackage());//类所在的包 package Reflect
//获取类的父类
System.out.println(aClass.getSuperclass());//class Reflect.User
//获取类的接口
Class<?>[] interfaces = aClass.getInterfaces();
System.out.println(interfaces.length);//0 Child类没实现任何接口
//获取类的属性
//Field是属性对象
Field f1 = aClass.getField("xxx");//根据传入的字符串如xxx来获取对应的属性,只能获取public
Field f2 = aClass.getDeclaredField("xxxx");//获取属性名为xxxx的属性,不论权限(包括private)
Field[] fields = aClass.getFields();//获取所有权限为public的属性
Field[] declaredFields = aClass.getDeclaredFields();//获取所有属性(包括private)
//获取类的方法
//Method是方法对象
Method m1 = aClass.getMethod("xx");//获取方法名为xx的方法,只能获取public修饰的方法
Method m2 = aClass.getDeclaredMethod("xxx");//获取名为xxx的方法,不论权限
Method[] methods = aClass.getMethods();//获取所有public修饰的方法
Method[] declaredMethods = aClass.getDeclaredMethods();//获取所有方法
//获取构造方法
//Constructor是构造器对象
Constructor<? extends User> constructor = aClass.getConstructor();
Constructor<?>[] constructors = aClass.getConstructors();
Constructor<? extends User> declaredConstructor = aClass.getDeclaredConstructor();
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
//获取权限(修饰符)
int modifiers = aClass.getModifiers();//多个修饰符融合成了1个int值
//Modifier提供方法来判断是否为xx修饰符,涉及位运算
boolean aProtected = Modifier.isProtected(modifiers);//判断是否有protected修饰符
System.out.println(modifiers);
System.out.println(aProtected);
}
}
class User {
public void test1(){
System.out.println("test1");
}
}
class Child extends User{
public void test2(){
System.out.println("test2");
}
}
用反射实现登录功能
package Reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws Exception{
//不直接创建对象,而是构造方法对象
//先拿到类对象
//有三种方式
Class employeeClass = Employee.class;//拿到了Employee这个类的信息,等同于拿到了字节码文件
/*
还有以下两种方式
Class<?> employeeClass = Class.forName("Reflect.Employee");//Class.forName("包名.类名")
Class<? extends Employee> employeeClass = new Employee().getClass();
*/
//再拿到构造方法对象
Constructor declaredConstructor = employeeClass.getDeclaredConstructor();
/*Employee类没写构造器,JVM会默认提供一个声明的无参构造器*/
//通过构造方法来构造实例
Object emp = declaredConstructor.newInstance();//构建出了Employee的对象emp
//实现登录验证需要获取属性
Field fUsername = employeeClass.getField("username");
Field fPassword = employeeClass.getField("password");
//属性赋值
fUsername.set(emp,"admin");//set赋值,(对象,值)
fPassword.set(emp,"123456");
//获取方法
Method mLogin = employeeClass.getMethod("login");
//调用方法
Object result = mLogin.invoke(emp);//调用emp的login(mLogin对应的login)方法
System.out.println(result);//true
}
}
class Employee {
public String username;
public String password;
public boolean login(){
if("admin".equals(username) && "123456".equals(password)){
return true;
}else {
return false;
}
}
}
反射最重要的用途就是开发各种通用框架。
类加载器
package Reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo {
public static void main(String[] args) throws Exception{
Class<User> userClass = User.class;//获取User类的信息
ClassLoader classLoader = userClass.getClassLoader();//获取类的加载器对象
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//核心类库 > 平台类库 > 自定义类
//自定义类的上一级就是平台类
System.out.println(classLoader.getParent());//sun.misc.Launcher$ExtClassLoader@1b6d3586
//jdk9后会把extclassloader改为platformclassloader
}
}
class User {}
String是核心类,获取它的加载器对象结果为null。因为启动类加载器采用操作系统平台语言实现