1class
Java除基本类型外其他都是class(包括interface)
- String
- Object
- Runnable
- Exception
- ...
String s = "Hello";
Object o = new Double(123.456);
Runnable r = new Thread();
Exception e = new RuntimeException();
- class(包括interface)的本质是数据类型(Type)。我们把一个对象实例赋值给一种数据类型变量时,必须严格按照数据类型赋值。
- 没有继承关系的数据类型是无法赋值的。Java定义了一种强数据类型关系,并且编译器会检查数据类型,不符合数据类型要求的,在赋值时,编译器就会报错。
Double d = new Double(123.456);
String s = new Double(123.456);//报错
- class/interface的数据类型就是Class
- 每加载一个class,JVM就为其创建一个Class类型的实例,并关联起来,Class实例是JVM内部创建的。
public final class Class {
private Class() {}
}
- JVM持有的每个Class实例都指向一个数据类型(class或interface)
class Class{
}
- 一个Class实例包含了该class的完整信息
例如String类的class
所以Java定义的Class类是:
- JVM为每个加载的class创建对应的Class实例,并在实例中保存该class的所有信息
- 如果获取了某个Class实例,则可以获取到该实例对应的class的所有信息。
- 通过Class实例获取class信息的方法成为反射(Reflection )
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着这个对象所属的类。可以通过专门的Java类访问这些信息,保存这些信息的类被称为Class类。
如何获取一个class的Class实例?
- Type.class
- getClass():通过调用Object类中的getClass()方法返回一个Class对象
- Class.forName(完整类名):在使用
Class.forName()
方法时,必须提供一个类的全名,这个全名包括类所在的包的名字。如果在调用该方法时,没有找到该路径的类,将会抛出ClassNotFoundException。
//方法1 (类名)Type.class
Class cls = String.class;
//方法2 如果有实例变量,通过getClass()来获取
String s = "Hello";
Class cls = s.getClass();
//方法3 通过Class.forName(),传入完整的类名获取
Class cls = Class.forName("java.lang.String");
Class实例在JVM中是唯一的,一个JVM只对应唯一的Class实例
- 可以用==比较两个Class实例
boolean b1 = cls1 == cls2; //true
boolean b2 = cls2 == cls3; //true
//用三种方法任意获取的class实例都指向同一个class对象,所以是true
Class实例比较和instanceof的差别:
Integer n = new Integer(123);
boolean b3 = n instanceof Integer; // true
boolean b4 = n instanceof Number; // true
boolean b1 = n.getClass() == Integer.class; // true
boolean b2 = n.getClass() == Number.class; // false
iinstanceof不但匹配当前类型,还匹配当前类型的子类,因为Integer为Number的子类,所以为true
但是用“==”判断class实例时只能精确的判断数据类型,不能做子类的比较
通常情况下,使用instanceof判断数据类型,因为面向抽象编程的时候,我们不关心具体的子类型;只有在需要精确判断某个类型是否是某个Class的时候,我们才是用“==“来判断
2Reflection
反射的目的是当获取某个Object实例时,我们可以获取该Object的class信息
从Class实例获取class信息:
- getName() 取完整的类名
- getSimpleName() 获取简单的类名
- getPackage() 获取包名
Class cls = String.class;
String fname = cls.getName(); // "java.lang.String";
String sname = cls.getSimpleName(); // "String";
String pkg = cls.getPackage().getName(); // "java.lang";
从Class实例判断class类型 :
- isInterface() 是否是接口类型
- isEnum() 是否是枚举类类型
- isArray() 是否是数组类型
- isPrimitive() 是否是基本类型
Runnable.class.isIntegerface(); // true
java.time.Month.class.isEnum(); // true
String[].class.isArray(); // true
int.class.isPrimitive(); // true
创建class实例:
- newInstance()
Class cls = String.class;
// new String():
String s = (String) cls.newInstance();
3动态加载
利用JVM动态加载的特性:
- 可以在运行期根据条件加载不同的实现类
boolean isClassPresent (String name) {
try {
Class.forName(name);
} catch (Exception e) {
return false;
}
}
利用JVM动态加载class的特性,可以在运行期根据条件加载不同的实现类
//Commons Logging 优先使用Log4j:
LogFactory factory;
if (isClassPresent ("org.apache.logging.log4j.Logger")){
factory = createLog4j();
} else {
factory = createJdkLog();
}
boolean isClassPresent (String name) {
try {
Class.forName(name);
return true;
} catch (Exception e){
return false;
}
}
Hello.java(接口)
public interface Hello {
public void hello();
}
Student.java
public class Student implements Hello{
private String name;
public Student() {
this("unNamed");
}
public Student(String name) {
this.name = name;
}
public void hello() {
System.out.println(name+" is Studnet");
}
}
Teacher.java
public class Teacher implements Hello{
private String name;
public Teacher() {
this("unNamed");
}
public Teacher(String name) {
this.name = name;
}
public void hello() {
System.out.println(name+" is Teacher");
}
}
Main.java
public class Main {
public static void main(String[] args) throws Exception{
Class cls = Student.class;
System.out.println("class name:" + cls.getName());
System.out.println("class simple name: " +cls.getSimpleName());
System.out.println("package name" +cls.getPackage().getName());
System.out.println("is interface?" + cls.newInstance());
//Student s = new Student();
Student s = (Student) cls.newInstance();
s.hello();
}
}
对代码进行修改,运行结果不变
public class Main {
public static void main(String[] args) throws Exception{
Class cls;
if(true) {
cls = Class.forName("com.xiaoxiatianxi.sample.Student");
}else {
cls = Class.forName("com.xiaoxiatianxi.sample.Teacher");
}
System.out.println("class name:" + cls.getName());
System.out.println("class simple name: " +cls.getSimpleName());
System.out.println("package name" +cls.getPackage().getName());
System.out.println("is interface?" + cls.newInstance());
//Student s = new Student();
Hello s = (Hello)cls.newInstance();
s.hello();
}
}
4总结
- JVM为每个加载的class创建对应的Class实例来保存class的所有的信息
- 获取一个class的Class实例后,就可以获取该class的所有信息
- 通过Class实例获取class信息的方法成为反射Reflection
- JVM总是动态加载class,可以在运行期根据条件控制加载class