JavaSE
一.类加载
步骤
1.加载
通过一个类的全限定名来获取定义此类的二进制字节流。把数据传输到内存中(字节码文件 —javac—> 内存 从文件到内存就需要一个字节流)在内存中生成一个代表这个类的java.lang.Class对象。作为方法区这个类的各种数据访问入口。
2.连接(绝大部分时间)
验证:确保被加载类的正确性(why编译器已经通过了,还要再检查一次呢? 因为有些熟悉字节码文件的人会自己编写字节码文件,跳过编译器的检查,为了避免这一部分人的误操作;还有一个文件直接改为 .class,这种文件没有Magic Number(即ca fe ba be,每个真正的字节码文件才有的),不会因此混入。)准备:负责为类的静态成员分配内存并设置默认初始化值解析:将类中的符号引用(编译相关,跟语言无关)替换为直接引用(把地址填进去)。
3.初始化
给静态成员变量赋初值(真正赋值,之前只是赋默认值),执行静态代码块。
类加载时机
创建该类的对象时调用该类的静态变量时调用该类的静态方法时使用反射方式创建每个类或接口的Class对象时初始化某个类的子类,会先触发父类的加载java.exe命令来运行某个主类(java 类名)
类加载器(jdk8)
只完成加载中的第一步。
Bootstrap ClassLoader 根类加载器 负责加载Java核心类的加载,在JDK中的JRE的lib中的rt.jar。(jar包是打包字节码文件的方式)JVM启动后就自动加载。Extension ClassLoader 扩展类加载器 加载JRE的扩展目录中jar包的加载(JDK中的JRE的lib目录下的ext目录中的jar包)System ClassLoader 系统类加载器 负责加载自己定义的Java类
二.反射
Java反射技术可以帮助我们在运行时发现和使用运行时的类型信息。即研究Class对象和它的使用
获取Class对象
通过该类对象对象获取
对象.getClass()
MyClass myClass
= new MyClass();
Class
classObj1 = myClass
.getClass();
class MyClass {
}
通过字面值常量
Class classObj = 类名.class
Class
classObj = MyClass
.class;
通过Class类的静态方法
static Class forName(String className) 返回给定字符串名 的类或接口的Class对象 Class.forName(“全类名”)。
Class
classObj = Class
.forName("com.google.www.reflection.getclass.MyClass")
注意事项:
第二种获取Class对象的方式比较简单,但是通过它触发类加载的过程不是一个完整的加载过程(类中的静态代码块没有执行,即没有完成类加载中的初始化工作)。相比较通过方式三获取Class对象,它所触发的类加载是一个完整的类加载过程。(学习数据库时需要使用)开发中一般用第3种办法,因为更加灵活
第三种方式的常用操作:
创建一个配置文件 resource bundle。后缀:.properties添加配置: 例:className(属性名)=com.google.www.reflection.getclass.MyClass(属性值) 注意,配置文件不需要双引号。读取配置文件中的配置信息
Properties properties
= new Properties();
FileInputStream fis
= new FileInputStream("配置文件");
properties
.load(fis
);
String className
= properties
.getProperty("className");
Class
aClass = Class
.forName(className
);
获取构造方法信息
Java中的所有构造方法都由一个类来描述Constructor,所以每个构造方法都是一个Constructor对象。
API
一次获取多个构造方法:
Contructor
[] getContructors()
Contructor
[] getDeclaredConstructors()
一次获取一个构造方法:
Constructor
<T> getConstructor(Class
... parameterTypes
)
Constructor
<T> getDeclaredConstructor(Class
... parameterTypes
)
注意事项:
1. 通过参数列表来区分不同的构造方法。获取单个构造方法是必须指明其参数列表。这些用法都是在已知构造方法的参数时使用的。
2. 参数列表中的参数类型要用对应的Class对象来表示。
例: Class
integerClass = int.getClass();
3. 数据类型
... 指可变参数,即参数是可变的。
public static void callVararg() {
varargMethod(1,2,3,4,5);
varargMethod(100);
varargMethod();
}
public static void varargMethod(int... a
) {
for(int i
= 0; i
< a
.length
; ++i
)
{
System
.out
.println(a
[i
])
}
}
获取多个构造方法:
Class
classObj = Class
.forName("全类名");
Contructor
[] constructors
= classObj
.getContructors();
System
.out
.println(Arrays
.toString(costructors
));
Contructor
[] declaredConstructors
= classObj
.getDeclaredConstructors();
System
.out
.println(Arrays
.toString(declaredConstructors
));
获取单个构造方法:
Properities properities
= new Properities();
FileInputStream fis
= new FileInputStream("配置文件");
properities
.load(fis
);
String s
= properities
.getProperity("属性名");
Class
classObj = Class
.forName(s
);
Constructor publicConstructor
= classObj
.getConstructor(int.class);
System
.out
.println(publicConstructor
);
Constructor privateConstructor
= classObj
.getDeclaredConstructor(int.class, double.class, String
.class);
System
.out
.println(privateConstructor
);
Constructor对象的使用:
Constructor对象
.newInstance(Object
... initargs
)
public class Demo1 {
Class
classObj = Class
.forName("全类名");
Constructor privateConstructor
= classObj
.getDeclaredConstructor(int.class, double.class, String
.class);
int intValue
= 1;
double doubleValue
= 2.5;
String str
= "zhangsan";
privateConstructor
.setAccessible(true);
ConstructorClass o
= (ConstructorClass
) privateConstructor
.newInstance(intValue
, doubleValue
, str
);
System
.out
.println(o
);
}
class ContructorClass {
int intValue
;
double doubleValue
;
String strValue
;
public ConstructorClass(int intValue
) {
this.intValue
= intValue
;
}
protected ConstructorClass(double doubleValue
) {
this.doubleValue
= doubleValue
;
}
ConstructorClass(int intValue
, double doubleValue
) {
this.intValue
= intValue
;
this.doubleValue
= doubleValue
;
}
private ConstructorClass(int intValue
, double doubleValue
, String strValue
) {
this.intValue
= intValue
;
this.doubleValue
= doubleValue
;
this.strValue
= strValue
;
}
public String
toString() {
return "ConstructorClass{" +
"intValue=" + intValue
+
", doubleValue=" + doubleValue
+
", strValue='" + strValue
+ '\'' +
'}';
}
}
获取成员变量信息
Java中的成员变量都由Field类来描述。一个Field对象对应一个成员变量。
API:
获取多个成员变量:
Filed
[] getFields()
Filed
[] getDelaredFields()
获取单个成员变量:
Field
getField(String name
);
Field
getDeclaredField(String name
);
用法:
Object
get(Object obj
);
void set(Object obj
, Object
new Value);
class FieldFather {
public int i
= 100;
public boolean sonI
;
private double j
= 6.6;
}
class FieldSon extends FieldFather {
public int sonI
;
protected double sonJ
;
String name
;
private Object obj
;
private int privateValue
= 1000;
public FieldSon(int sonI
, double sonJ
, String name
, Object obj
) {
this.sonI
= sonI
;
this.sonJ
= sonJ
;
this.name
= name
;
this.obj
= obj
;
}
@Override
public String
toString() {
return "FieldSon{" +
"sonI=" + sonI
+
", sonJ=" + sonJ
+
", name='" + name
+ '\'' +
", obj=" + obj
+
", privateValue=" + privateValue
+
"} ";
}
}
Class
sonClass = FieldSon
.class;
Field
[] fields
= sonClass
.getFields();
System
.out
.println(fields
);
Field
[] declaredFields
= sonClass
.getDeclaredFields();
System
.out
.println(declaredFields
);
Field sonI
= sonClass
.getField("sonI");
Field protectedField
= sonClass
.getField("sonJ");
Field privateField
= sonClass
.getDeclaredField("obj");
System
.out
.println(privateField
);
Class
fieldSon = FieldSon
.class;
FieldSon fieldSon
= new FieldSon(1,6.6,"张三",null
);
Field privateField
= fieldSon
.getDeclaredField("privateValue");
int privateValue
= (int) privateField
.get(fieldSon
);
privateField
.setAccessable(true);
privateField
.set(fieldSon
,2000);
获取成员方法信息
API
Java中所有的成员方法都是由一个Method类描述的,一个Method对象对应一个方法。
Method
[] getMethods()
Method
[] getDeclaredMethods()
通过方法签名指定:方法名
+参数列表
Method
getMethod(String name
, Class
... parameterTypes
);
Method
getDeclaredMethod(String name
, Class
... parameterTypes
);
Object
invoke(Object obj
, Object
... args
)
Method对象
.invoke(调用该方法的对象
,方法运行的实际参数
);
class MethodClass {
public int publicMethod(int a
, String b
){
return 0;
}
protected String
protectedMethod() {return "zhangsan";}
void defaultMethod() {}
private double privateMethod(boolean flag
, double a
, char c
) {
System
.out
.println("privateMethod");
return 0.5;
}
}
Class
methodClass = MethodClass
.class;
Method
[] methods
= methodClass
.getMethods();
System
.out
.println(Arrays
.toString(methods
));
Method
[] declaredMethods
= methodClass
.getDeclaredMethods();
System
.out
.println(Arrays
.toString(declaredMethods
));
Method publicMethod
= methodClass
.getMethod("publicMethod", int.class, String
.class);
System
.out
.println(publicMethod
);
Method privateMethod
= methodClass
.getDeclaredMethod("privateMethod",boolean.class,double.class,char.class);
System
.out
.println(privateMethod
);
Method privateMethod
= methodClass
.getDeclaredMethod("privateMethod",boolean.class,double.class,char.class);
MethodClass obj
= new MethodClass();
privateMethod
.setAccessible(true);
double a
= (double) privateMethod
.invoke(obj
,true,8.8,'a');
获取静态变量和静态方法
静态变量和方法的获取与普通变量和方法相同,区别在于使用上无需指定类的对象。
class StaticClass {
static int a
= 30;
private static boolean staticMethod() {
return false;
}
}
Class
staticClass = StaticClass
.class;
Field a
= staticClass
.getDeclaredField("a");
int o
= (int)a
.get(null
);
System
.out
.println(o
);
a
.set(null
,300);
System
.out
.println(staticClass
.a
);