JavaSE核心API--Java反射机制与Object类
java.lang.reflect.Method
1)理论讲解:可变长参数(JDK1.5之后推出的新特性)
代码演示:
public static void main(String[] args) {
dosome(1,1.1);
dosome(1,1.1,"a");
dosome(1,1.1,"a","b");
dosome(1,1.1,"a","b","c");
}
public static void dosome(int a,double d,String... s) {
System.out.println("lenth:"+s.length);
System.out.println(Arrays.toString(s));
}
2)附件:用于测试反射的类
public class Person {
public void sayHello() {
System.out.println("大家好!");
}
public void sayHi() {
System.out.println("hi!");
}
public void sayName(String name) {
System.out.println("大家好!我是"+name);
}
public void say(String name,int age) {
System.out.println("大家好!我是"+name+",今年"+age+"岁了!");
}
}
3)理论讲解:反射机制
反射是java中的动态机制,它允许我们实例化对象,调用方法或属性从原来的编码期确定转为在程序运行期决定
反射提高了灵活度,但是会降低性能,因此适度使用
class类
class类的每一个实例用于表示JVM加载的一个类
所以我们也称其为"类的类对象"
JVM加载的每个类都有且只有唯一的一个Class实例与之对应,我们可以获取某个类的类对象
通过它我们可以得知该类的一切信息(类名,有哪些属性,哪些方法等)
甚至可以动态实例化这个类的对象,并调用它的属性和方法
获取一个类的类对象有以下几种方式:
1.每个类都有一个静态属性:class
用于获取该类的类对象,当我们确定要获取某个类的类对象时可以用这种方式,但由于通过硬编码调用,所以不灵活
如:
Class cls=String.class;
Class cls=int.class;
2.调用Class的静态方法:forName(String name)
该方法要求传入要加载的类的完全限定名
包名.类名
如:
Class cls=Class.forName("java.lang.String")
3.使用类加载器:ClassLoader
代码演示:
try {
// Class cls=Class.forName("java.lang.String");
// Class cls=Class.forName("reflect.Person");
/*
* java.util.ArrayList
* java.lang.Integer
* java.io.InputStream
*/
Scanner scan=new Scanner(System.in);
System.out.println("请输入要加载的类的名字:");
String className=scan.nextLine();
Class cls=Class.forName(className);
scan.close();
//获取类名
String name=cls.getName();
System.out.println(name);
//获取所有方法(包括从超类继承的方法)
Method[] methods=cls.getMethods();
//获取当前类自己定义的方法(不含从超类继承的)
// Method[] methods=cls.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
4)理论讲解:通过Class进行实例化
代码演示:
// 实例化Person
Person p = new Person();
System.out.println(p);
System.out.println("请输入要实例化的类名:");
String className = new Scanner(System.in).nextLine();
// 1.加载需要实例化的类的类对象
Class cls = Class.forName(className);
// 2.通过类对象快速实例化
Object obj = cls.newInstance();
System.out.println(obj);
5)理论讲解:利用反射调用方法
利用反射
1.加载类对象
2.通过类对象实例化
3.获取该类定义的需要调用的方法
4.执行该方法
代码演示:
Person p = new Person();
p.sayHello();
/*
* 类名和方法名都可以写入xml文档中,程序运行的时候去读取xml文件即可
*/
Scanner scan = new Scanner(System.in);
System.out.println("请输入要实例化的类:");
String className = scan.nextLine();
System.out.println("请输入要执行的方法:");
String methodName = scan.nextLine();
scan.close();
/*
* 1.加载类对象
*/
Class cls = Class.forName(className);
/*
* 2.通过类对象进行实例化
*/
Object obj = cls.newInstance();
/*
* 3.获取要调用的方法 Method的每一个实例用于表示一个类中定义的一个方法
*/
Method method = cls.getDeclaredMethod(methodName);
/*
* 4.调用该方法
*/
method.invoke(obj);
6)理论讲解:利用反射调用有参数的方法
代码演示:
Person p = new Person();
p.sayName("杰克");
// 利用反射
Class cls = Class.forName("reflect.Person");
Object obj = cls.newInstance();
/*
* sayName(String)
*/
// Method method=cls.getDeclaredMethod("sayName",String.class);
// method.invoke(obj, "汤姆");
/*
* sayName(String,int)
*/
Method method = cls.getDeclaredMethod("say", String.class, int.class);
method.invoke(obj, "杰森", 15);
补充:Object类
测试类
public class Person {
private int age;
// public Person(int age) {
// super();
// this.age = age;
// }
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0 || age > 100) {
return;
}
this.age = age;
}
}
使用当前类测试Object常用方法
public class Point {
/**
* 特征/属性-----值不一样为变量,值都一样为常量
* 行为/方法---传参的值不同,返回的结果也不一样
*/
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
/**
* 重写toString方法 toString方法是一个非常常用的方法,很多API的操作都会间接调用该方法
* 方法的目的是将当前对象转换为字符串,具体返回的字符串格式没有固定要求
* 遵循的原则是返回的内容中包含当前对象的属性信息,可以通过该字符串的内容直观反应当前对象的内容
*/
public String toString() {
String str = "(" + x + "," + y + ")";
return str;
}
/**
* Object定义的equals方法的设计意图是比较两个对象的内容是否相同
* 如果不重写该方法,那么Object内部是用"=="比较的,这样就失去量equals比较的意义了
* 所以当我们需要调用一个类的equals时,该方法就应当重写
* 注:java提供的类大部分都已经重写过了,只有我们自定义的类需要自行重写
*
* p.equals this:p o
*
*/
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
if (o instanceof Point) {
Point p = (Point) o;
return this.x == p.x && this.y == p.y;
}
return false;
}
}
理论讲解:
Object的toString方法的设计意图就是将当前类的实例对象转换为一个字符串
Object已经实现了toString方法,默认返回当前对象的句柄(类名@地址)
但实际上对我们的开发没有什么帮助,所以通常我们会重写这个方法
注:java定义的类都已经实现了toString方法,只有我们自己定义的类若需要使用该方法,要自行重写
代码演示:
// Person p=new Person();
// p.setAge(555);
// System.out.println(p.getAge());
Point p = new Point(1, 2);
String str = p.toString();
System.out.println(str);// 结果输出为对象p的引用信息
System.out.println(p);
/*
* 一个引用类型在和字符串连接操作时,也是先调用该引用类型的toString方法将其转换为字符串后才和字符串做连接操作的
*/
String line = "point:" + p;
System.out.println(line);
Point[] arr = { new Point(2, 3), new Point(3, 4), new Point(4, 5) };
System.out.println(Arrays.toString(arr));
Point p2 = new Point(1, 2);
System.out.println("p==p2:" + (p == p2));// false
System.out.println("equals:" + p.equals(p2));// ?