一 .反射
反射的一个重要条件就是首先要获取class对象,而获取class的方式有以下几点:
(1)通过getclass对象来获取class对象;
(2)通过类名.class来获得;
(3)通过class.forName()来获取class对象;
例如:
class Student{
public int age;
private String name;
public Student(){
}
private Student(String name) {
this.name = name;
}
public void fun1() {
System.out.println("fun1()");
}
private void fun2() {
System.out.println("fun2()");
}
public String getName() {
return this.name;
}
}
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException {
Student s1 = new Student();
Class c1 = s1.getClass();//通过 getClass 对象来获取Class对象
System.out.println(c1);
Class c2 = Student.class;//通过 类名.Class 来获取
System.out.println(c2);
Class c3 =Class.forName("Student");//通过 forname 的静态方法来获取 任何一个类都有一个隐含的静态成员变量 class
System.out.println(c3);
}
}
面试题:
(1)一个class里面有几个class对象?
答:一个class类里有一个对应的class对象,通过加载 ,链接,编译后生成.class文件,就产生一个class对象,用来表示这个类的信息。
(2)反射里三个重要的类型?
答: 1.Field(类的属性) Metho(类的方法) Constructor(类的构造函数)
下面是反射的一些典型的方法:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):
获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
getDeclaredConstructor():这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
class Student{
public int age;
private String name;
public Student(){
}
private Student(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void fun() {
System.out.println("fun1()");
}
private void fun2() {
System.out.println("fun2()");
}
public String getName() {
return this.name;
}
}
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Student s1 = new Student();
Class c2 = Student.class;//通过 类名.Class 来获取
System.out.println(c2);
Field[] fileds = c2.getDeclaredFields();//获取类的所有属性 包括私有属性
for (Field field : fileds) {
System.out.println(field.getName());
Method[] methonds = c2.getDeclaredMethods();//获得类的所有方法
for (Method methond : methonds) {
System.out.println(methond.getName());
Field f1 = c2.getField("age");//获取指定的属性public
System.out.println(f1);
Field f2 = c2.getDeclaredField("name");//抛出异常 //获取private私有属性
f2.setAccessible(true); //启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
System.out.println(f2);
Student p3 = (Student) (c2.newInstance());//newInstancefang方法
f2.set(p3, "gff");
System.out.println(f2.get(p3));
//通过类的不带参数的构造函数创建这个类的对象;
Class c3 = Student.class;
Constructor c1 = c3.getDeclaredConstructor();
c1.setAccessible(true);
Student p1 = (Student) c1.newInstance();
System.out.println("无参数的私有构造函数\t" + p1);
Constructor c1 = c2.getDeclaredConstructor(String.class);
c1.setAccessible(true);
Student p1 = (Student) c1.newInstance("gff");
System.out.println("有参数的构造函数\t" + p1.getName());
}
}
}
二 .枚举
枚举是个抽象类,它不可以产生实例对象,原因是:自定义继承了Enum,构造函数默认为私有,枚举还可以作为switc的参数。
(1),枚举的构造函数时私有的
(2),每一个枚举成员都代表的是一个自身对象
(3)枚举一样可以定义方法,重载构造函数,定义抽象方法,然后让每一个成员去实现这个抽象方法,与普通类一样。
enum Animals{
DOG,PIG,CAT,BIRD//都是实例
}
public class Demo2 { //枚举可以作为switch的参数
public static void main(String[] args) {
Animals animals = Animals.BIRD;
switch (animals){
case CAT:
System.out.println("cat");
break;
case DOG:
System.out.println("dog");
break;
case PIG:
System.out.println("pig");
break;
case BIRD:
System.out.println("bird");
break;
default:
System.out.println("==============");
}
}
}
枚举中的一些方法:
name()返回此枚举常量的名称,在其枚举声明中对其进行声明
ordinal()返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)
toString(),返回枚举常量的名称,它包含在声明中,name()方法与toString()几乎是等同的,都是输出变量的字符串形式。
compareTo(E o) ,比较此枚举与指定对象的顺序
getDeclaringClass(),返回与此枚举常量的枚举类型相对应的 Class 对象
equals(Object other) 当指定对象等于此枚举常量时,返回 true。
valueOf(Class enumType, String name)返回带指定名称的指定枚举类型的枚举常量。
values()把枚举的实例 都变成一个数组这个方法是由编译器生成的静态方法
enum Animals {
DOG, PIG, CAT, BIRD//都是实例
}
public class Demo2 { //枚举可以作为switch的参数
public static void main(String[] args) {
Animals animals = Animals.BIRD;
Animals animals1 = Animals.CAT;
System.out.println(animals.ordinal());//枚举常量的序数
System.out.println(animals.toString());//枚举常量的名称
System.out.println(animals.valueOf("CAT"));//指定名称的指定枚举类型的枚举常量。
System.out.println(animals.name());//枚举常量的名称
System.out.println(animals.compareTo(animals1));//比较此枚举与指定对象的顺序
System.out.println(animals.getDeclaringClass());//返回与此枚举常量的枚举类型相对应的 Class 对象
System.out.println(animals.equals(animals1));//当指定对象等于此枚举常量时,返回 true,否则为false。
/* for (Animals a:Animals.values()
) {
System.out.println(a);*/ //values把枚举的实例 都变成一个数组这个方法是由编译器生成的静态方法
Animals[] animals2 = Animals.values();
for (int i = 0; i < animals2.length; i++) {
}
System.out.println(Arrays.toString(animals2));
}
}
public enum TestEnum1 {
DOG("dog",1), PIG("pig",2), CAT("cat",3), BIRD("bird",4);//都是实例
private final String name;
private final int key;
private TestEnum1(String name,int key){
this.name = name;
this.key = key;
}
public static TestEnum1 getkey(int key){
for (TestEnum1 animals:TestEnum1.values()
) {
if (animals.key == key){
return animals;
}
}
return null;
}
public static void main(String[] args) {
getkey(4);
System.out.println(getkey(4).toString());
}
}
在枚举类中构造函数都是默认私有的,但是枚举类的私有构造方法是不能通过反射机制去调用的
枚举中不能newInstance()
if ((clazz.getModifiers() & Modifier.ENUM) != 0)//如果给定的对象是枚举类型的就会抛出下面的这个异常
throw new IllegalArgumentException(“Cannot reflectively create enum objects”);
public enum TestEnum1 {
DOG, PIG, CAT,BIRD;
private TestEnum1(){//不带参数的构造函数
}
/* DOG("dog",1), PIG("pig",2), CAT("cat",3), BIRD("bird",4);//都是实例
private final String name;
private final int key;
private TestEnum1(String name,int key) {//带参数的构造函数
this.key = key;
this.name = name;
}*/
/* public void getInstance(){
TestEnum1 testEnum1 = new TestEnum1();
}*/
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class animalEnum1 = TestEnum1.class;
Constructor constructor = animalEnum1.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
TestEnum1 p = (TestEnum1)constructor.newInstance();
System.out.println("无参数的构造函数\t" + p);
/*onstructor constructor = animalEnum1.getDeclaredConstructor(String.class,int.class,String.class,int.class);
constructor.setAccessible(true);
TestEnum1 p = (TestEnum1)constructor.newInstance("pig","猪");
System.out.println("有参数的构造函数\t"+p);*/
}
}
三 .异常
throwable是基类,他派生出错误(Error)和(Exception)
Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。
最典型的两个1.OutOfMemoryError 堆溢出
2.StackOverFlowError 栈溢出
Exception(异常):是程序本身可以处理的异常
异常又分为运行时期的异常和编译时期的异常,
有异常我们就要捕获异常:try -catch
有时我们也会用到:try - catch - finally
常见的异常:
1.数组越界:
public class lx2 {
public static void main(String[] args) {
int a[] = {1,2,3,4};
try {
System.out.println(a[4]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组越界");
e.printStackTrace();
}
}
}
算术运算:
public class lx2 {
public static void main(String[] args) {
try {
int a = 10;
int b = a/0;
System.out.println(b);
}catch (ArithmeticException e){
System.out.println("算术运算异常");
e.printStackTrace();
}
}
}
public static void main(String[] args) {
String str = null;
if (str == null) {
throw new NullPointerException("str == null");
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try{
int a = scanner.nextInt();
int b = scanner.nextInt();
int result =devide(a,b);
System.out.println("result:"+ result);
}catch (ArithmeticException e){//算术运算异常
System.out.println("ArithmeticException异常");
e.printStackTrace();
}catch (InputMismatchException e){//输入异常
System.out.println("InputMismatchException异常");
e.printStackTrace();
}finally {
scanner.close();
}
}
public static int devide (int a, int b ){
return a / b ;
}
}
class SimpieException extends Exception{
public SimpieException(String gff){
super(gff);//带有参数的
}
}
public class Test {
public static void fun() throws SimpieException {
throw new SimpieException("gff");
}
public static void main(String[] args) {
Test test = new Test();
try {
test.fun();
} catch (SimpieException e) {
System.out.println("SimpieException 异常");
e.printStackTrace();
}
}
}
finall解析:
在try - catch - finall里面的执行顺序:
public class Test {
public static int Num(){
int a = 3;
try {
System.out.println("1");
a = 3/0;
return 0;
} catch (Exception e){
System.out.println("2");
return 1;
}finally {
System.out.println("3");
}
}
public static void main(String[] args) {
System.out.println("return value of Num:"+ Num());
}
}
说明了 finally 语句块在 catch 语句块中的 return 语句之前执行。
finally 中的 return 会覆盖 try 或者 catch 中的返回值
public class Test {
public static int Num(){
try{
return 1;
}finally {
return 2;
}
}
public static void main(String[] args) {
int result = Num();
System.out.println(Num());
}
}
Num开始执行进入try中,返回异常执行return1,finally做后执行时,返回值变为2,所以最后的打印为2,后面的值覆盖了前面的值,而最后打印调用的是被覆盖的值。
四.final和finalize的区别;
1.final 修饰变量成为常量;final 修饰类,表示密封类,不能再被继承;final 修饰方法,表示该方法在子类中不能 被重写 。
2.finally 用于异常处理,try 块中的代码不管有没有发生异常,finally 块的代码都会执行的,一般用于释放资源 。
3.finalize 用于对象的回收,在 GC 回收某个对象的时候,对象的 finalize 方法会被先执行一遍 。
finally用的时候需要注意的:
(1)不要在fianlly中使用return。
(2)不要在finally中抛出异常。
(3)减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。
(4) 将尽量将所有的return写在函数的最后面,而不是try … catch … finally中。