一、 Java是静态语言
在运行期间,如果我们要产生某个类的对象,java虚拟机会检查该类型的Class对象是否被加载。如果未被加载,JVM会根据类的名称找到.class文件并加载它,一旦某个类型的class对象已被加载到内存,就可以用它来产生该类型的所有对象。
面向对象的思维:万事万物皆对象
类似于Class对象: 二、获取字节码的四种方式
public class Test {
public static void main(String[] args) throws Exception {
//方式1:通过getClass()方式获取
Person p = new Person();
Class c1 = p.getClass();
//方式2:通过内置class属性
Class c2 = Person.class;
//方式3:用的最多 调用Class类提供的静态方法forName
Class c3 = Class.forName("com.zhaoss.test02.Person");
//方法4:利用类的加载器
ClassLoader loader = Test.class.getClassLoader();
Class c4 = loader.loadClass("com.zhaoss.test02.Person");
}
}
三、作为Class类的实例的种类
//Class类的具体的实例:
//(1)类:外部类,内部类
Class c1 = Person.class;
//(2) 接口
Class c2 = Comparable.class;
//(3) 注解
Class c3 = Override.class;
//(4) 数组
int[] arr1 = {1,2,3};
Class c4 = arr1.getClass();
int[] arr2 = {4,5,6};
Class c5 = arr2.getClass();
// true -- 同一个维度,同一个元素类型(int),得到的字节码就是同一个
System.out.println(c4==c5);
//(5) 基础数据类型
Class c6 = int.class;
//(6) void
Class c7 = void.class;
四、获取信息
定义注释
/*
@Target:定义当前注解能够修饰程序中的哪些元素
@Retention:定义注解的声明周期
*/
@Target({TYPE,FIELD,METHOS,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();//属性
}
parameter [pəˈræmɪtə(r)] 参数 retention 保留;保持 policy 策略
dafa variable [ˈveəriəbl] 变量
@MyAnotation(value="hello")
public class Student extends Person implements MyInterface{
//属性:
private int sno;//学号
double height;//身高
protected double weight;//体重
public double score;//成绩
//方法:
@MyAnnotation(value="himethod")
public String showInfo(){
return "我是一名三好学生";
}
public String showInfo(int a,int b){
return "重载方法====我是一名三好学生";
}
private void work(){
System.out.println("我以后会找工作--》成为码农 程序员 程序猿 程序媛");
}
void happy(){
System.out.println("做人最重要的就是开心每一天");
}
protected int getSno(){
return sno;
}
//构造器
public Student(){
System.out.println("空参构造器");
}
private Student(int sno){
this.sno = sno;
}
Student(int sno,double weight){
this.sno = sno;
this.weight = weight;
}
protected Student(int sno,double height,double weight){
this.sno = sno;
}
@Override
@MyAnnotation(value="hellomyMethod")
public void myMethod() {
System.out.println("我重写了myMethod方法。。");
}
@Override
public String toString() {
return "Student{" +
"sno=" + sno +
", height=" + height +
", weight=" + weight +
", score=" + score +
'}';
}
}
①获取构造器和实例:
//获取字节码信息
Class cls = Student.calss;
//通过字节码信息获取构造器
//getConstructors只能获取当前运行时类的 被public修饰的构造器
Constructor[] c1 = cls.getConstructors();
//getDeclaredConstructors:获取运行时类的全部修饰符的构造器
//declared [dɪˈkleəd]公开宣布(声明)的
Constructor[] c2 = cls.getDeclaredConstructors();
//获取空参数的构造器 - public
Constructor c3 = cls.getConstructor();
//得到两个参数的有参构造器 -- public
Constructor c4 = cls.getConstructor(double.class, double.class);
//得到一个参数的有参构造器--private
Constructor c5 = cls.getDeclaredConstructor(int.class);
//创建对象
Object o1 = c3.newInstance();
Object o2 = c4.newInstance(180.3, 170.5);
②获取属性,并赋值 field [fiːld]字段
//getFields:获取运行时类和父类中被public修饰的属性
Field[] fields = cls.getFiedls();
//获取运行时类中的所有属性
cls.getDeclaredFields();
//获取指定属性
cls.getField("score");
cls.getDeclaredField("sno");
//获取属性的修饰符
Modifier.toString(sno.getModifiers());
//属性的数据类型
Class class = sno.getType();
class.getName();
//属性的名字
sno.getName()
//给属性赋值
Field sco = cls.getField("score");
Object obj = cls.newInstance();
sco.set(sco,98);
③ 获取方法和调用方法
//获取运行时类和所有父类中的public的方法,包括Object类的方法
cls.getMethods()
//获取运行时类中的所有方法
cls.getDeclaredMethods();
//获取指定的方法
cls.getMethod("showInfo");
cls.getMethod("showInfo",int.class,int.class);
cls.getDeclaredMethod("work");
//获取方法的具体结构
/* @注解
* 修饰符 返回值类型 方法名(参数列表) throw XXX{}
*/
//方法名称
work.getName()
//修饰符
work.getModifiers()
//返回值
work.getReturnType()
//参数列表
work.getParameterTypes()
//获取注解 只能获取生命周期是运行时的注解-----RetentionPolicy.RUNTIME
//@Override 声明周期是SOURCE,只编译器,只会在编译器的校验,运行时获取不到
work.getAnnotations()
//获取异常
work.getExceptionTypes()
//调用方法
Object o = cls.newInstance();
work.invork(o);
showInfo.invoke(o,12,45);
④获取类的接口、所在包、注解
//获取运行时类的接口
cls.getInterfaces();
//获取父类的接口
//先得到父类的字节码信息
Class superclass = cls.getSuperclass();
//得到接口
superclass.getInterfaces();
//运行时类所在包
Package aPachage = cls.getPachage();
aPachage.getName();
//获取运行时类的注解
cls.getAnnotations()
五 面试题
① 创建Person的对象,以后用new Person()创建,还是反射创建
实际上此问题是在问什么情况下会用反射,平时用new即可,运行时才能确定使用的对象,动态性,比如选择微信还是支付宝支付
② 反射是否破坏了面向对象的封装性
private 修饰的字段,反射可以访问,本质上是破坏了,但不能这么说。比如反射要访问private的字段,可以在定义的时候,直接定义为public。
比如女厕所门上贴的是女,但是还是有变态会进去,不能因为有变态,就把门口的女字去掉