反射
对任一类,能知道该类的所有属性和方法;对任一对象,能调用它的任意方法和属性
获取Class对象
要想对类进行反射,首先需要获取类的对象,有三种方法
每个类的Class对象数量只有一个
1.通过getClass获取对象
People p1 = new People();
Class c1 = p1.getClass();
2.类名.class
Class c2 = People.class;
3.通过Class对象的forName()静态方法
在使用该方法时可能抛出ClassNotFoundException异常
Class c3 = Class.forName("People");
反射方法
在诸多反射方法中存在三个最重要的类型
1.Filed[] 获取类的所有属性
getDeclaredFields中Declared的含义为私有属性的获取,如在方法中不加该修饰词,则只会获得类中的public属性
//获取获取类的所有属性
Field[] fileds = c1.getDeclaredFields();
for(Field field : fileds){
System.out.println(field.getName());
}
//获取类中私有属性name
Field f1 = c1.getDeclaredField("name");
2.Method[] 获取类的所有方法
Method[] methonds = c2.getDeclaredMethods();
for(Method methond : methonds){
System.out.println(methond.getName());
}
3.Constructor 获取类的构造方法
在获取到类的构造方法后,可以用setAccessible(true) 启用访问安全检查的开关,即如果该类的构造函数为private的,可以通过class对象给该类创建一个实例对象
//获取People类中无参数的构造方法
Constructor c2=c1.getDeclaredConstructor();
c2.setAccessible(true);
People p1=(People)c1.newInstance();
System.out.println("无参数的私有构造函数\t"+p1);
//获取People类中有参数的私有构造方法,并给定一个参数 “Allen”
Constructor c3 = c1.getDeclaredConstructor(String.class);
c3.setAccessible(true);
People p2=(People)c3.newInstance("Allen");
System.out.println("有参数的构造函数\t"+p2.getName());
枚举
如下所示即为一个简单的枚举类,枚举类中的每个数据成员都是一个对象,例如Color类中的RED,GREEN
public enum Color{
RED,GREEN,BLUE,BLACK;
}
枚举类不可以产生实例对象,因为自定义的枚举,都是继承
枚举类是一个抽象类,在枚举类中构造函数都是默认私有的,但是枚举类的私有构造方法是不能通过反射机制去调用的 因为在源代码中的Constructor类的
newInstance方法中存在下述语句:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
这表明如果用newInstance方法去反射枚举类中的私有构造函数,会抛出IllegalArgumentException异常
枚举类中的方法
enum Color{
RED,GREEN,BLUE,BLACK;
- 返回当前实例,及其序号
public class TestDemo1 {
public static void main(String[] args) {
Color color = Color.BLACK;
Color color1 = Color.BLUE;
//序号
System.out.println(color.ordinal());//3
//返回当前实例
System.out.println(color.name());//BLACK
System.out.println(color.toString());//BLACK
System.out.println(Color.valueOf("BLACK"));//BLACK
}
}
- 枚举实例的比较
public class TestDemo1 {
public static void main(String[] args) {
Color color = Color.BLACK;
Color color1 = Color.BLUE;
Color color2 = Color.BLACK;
//比较
System.out.println(color.equals(color1));//false
System.out.println(color.equals(color2));//true
System.out.println(color == color1);//false
System.out.println(color == color2);//true
}
}
- 比较序号差值
public class TestDemo1 {
public static void main(String[] args) {
Color color = Color.BLACK;
Color color1 = Color.BLUE;
Color color2 = Color.BLACK;
//color.compareTo(color1) color序号-color1序号
System.out.println(color.compareTo(color1));// 1
System.out.println(color.compareTo(color2));// 0
}
}
- values方法
values把枚举的实例,都变成一个数组
public class TestDemo1 {
public static void main(String[] args) {
//values把枚举的实例,都变成一个数组,这个方法是由编译器自己生成的
//静态方法
for (Color c : Color.values()
) {
System.out.println(c);
}
}
}
输出结果
在枚举类中创建有参数的构造函数
public enum Color {
RED(1), GREEN(2), BLUE(3), BLACK(4);
private final int id;
Color(int id) {
this.id = id;
}
}
异常
java中的异常主要包括两个子类,:Exception(异常)和 Error(错误)
Error(错误)
Error是程序无法处理的错误,表示运行应用程序中较严重问题,表示代码运行时 JVM(Java 虚拟机)出现的问题。
StackOverFlowError表示栈溢出异常
OutOfMemoryError 表示堆溢出异常
Exception(异常)
Exception 类有一个重要的子类 RuntimeException,RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。
抛出异常
例子:
运行期间的异常:
public class TestDemo3 {
public static void main(String[] args) {
int a = 10;
int d = a/0;
System.out.println(d);
}
}
输出结果:
编译期间的异常
public class TestDemo3 {
//在需要抛出异常的方法后添加 throws 异常类型
public static void main(String[] args) throws ClassNotFoundException {
//.forName("People") 需要抛出ClassNotFoundException异常
Class c1 = Class.forName("People");
}
}
try ……catch捕获异常并打印
运行顺序为先运行try中的语句,如果遇到异常,则从异常位置开始跳至catch语句中执行,try中异常位置之后的语句不再执行
public class TestDemo3 {
public static void main(String[] args) {
try {
int[] array = {1, 2, 3, 4};
System.out.println(array[4]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("有异常");
e.printStackTrace(System.out);
}
}
}
输出结果:
try ……catch之后的finally
finally中的语句在try和catch中语句执行之后才会执行,如果try,catch和finally中存在返回值,finally中的返回值会覆盖 try 或者 catch 中的返回值。
如:
public class TestDemo3 {
public static void main(String[] args) {
System.out.println(test());
}
public static int test() {
try {
int a = 10;
int b = a/0;
System.out.println(b);
return 1;
}catch (Exception e) {
System.out.println("有异常");
e.printStackTrace(System.out);
return 2;
}finally {
return 3;
}
}
}
在上面的程序中,无论是去掉try中的return 1,或者去掉catch中的return 2,最终的返回值都会是3,如下图所示
finally使用的注意事项
- 不要在fianlly中使用return。
- 不要在finally中抛出异常。
- finally中不要做一些其它的事情,仅仅用来释放资源是最合适的。
- 尽量将所有的return写在函数的最后面,而不是try … catch … finally中。
final finally finalize 的区别
1.final 修饰变量成为常量;final 修饰类,表示密封类,不能再被继承;final 修饰方法,表示该方法在子类中不能 被重写
2.finally 用于异常处理,finally 中的代码无论如何都会执行,一般用于释放资源
3.finalize 用于对象的回收,在 GC 回收某个对象的时候,对象的 finalize 方法会被先执行一遍