Class类简介
Class类
Java中所有的类、接口、枚举、注解、数组、基本数据类型、void关键字,都有Class对象。通过Class对象可以得到类的完整结构,一个Class对象在jvm中只有一个实例。
文章图片
获取类实例测试代码
package com.kuang;
public class Test {public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是 " + person.name);
//方式一 通过getClass()获取类
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二 通过forName获取类 可以获取到静态的类
Class c2 = Class.forName("com.kuang.Student");
System.out.println(c2.hashCode());
//方式三 通过类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//方式4 基本内置类型的 `包装类` 都有一个Type属性 通过该属性获得
Class c4 = Integer.TYPE;
System.out.println(c4);
// 获取父类的类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}class Person {
public String name;
public Person() {}public Person(String name) {
this.name = name;
}@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}class Student extends Person {
public Student() {
this.name = "学生";
}
}class Teacher extends Person {
public Teacher() {
this.name = "老师";
}
}
package com.kuang;
//哪些类有class对象import java.lang.annotation.ElementType;
public class Test2 {public static void main(String[] args) {
Class c1 = Object.class;
//类
Class c2 = Comparable.class;
//接口
Class c3 = String[].class;
//一维数组
Class c4 = int[][].class;
//二位数据
Class c5 = Override.class;
//注解
Class c6 = ElementType.class;
//枚举
Class c7 = Integer.class;
//基本类型的包装类
Class c8 = void.class;
//void
Class c9 = Class.class;
///Class
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
//输出结果注意数组的输出结果有点特殊
//class java.lang.Object
//interface java.lang.Comparable
//class [Ljava.lang.String;
//class [[I
//interface java.lang.Override
//class java.lang.annotation.ElementType
//class java.lang.Integer
//void
//class java.lang.Class
}
}
Class类实际是一个泛型类。
文章图片
Class常用方法
文章图片
JAVA内存分析
文章图片
java类装载过程分为3步:
文章图片
文章图片
1、加载 Jvm把class文件字节码加载到内存中,并将这些静态数据装换成运行时数据区中方法区的类型数据,在运行时数据区堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。
注:方法区不仅仅是存放方法,它还存放的是类的类型信息(class对象)。2、链接 执行下面的校验、准备和解析步骤,其中解析步骤是可选的
- 校验:检查加载的class文件的正确性和安全性
- 准备:为类变量(static)分配存储空间并设置类变量初始值(变量类型的默认值),类变量随类型信息存放在方法区中,生命周期很长,使用不当很容易造成内存泄漏。
- 解析:jvm将常量池内的符号引用(常量名)转换为直接引用(地址)
Class.forName和ClassLoader的区别? 在了解了类装载过程之后我们继续比较二者区别:
Classloder.loaderClass(String name)
其实该方法内部调用的是:Classloder. loadClass(name, false)
方法:Classloder. loadClass(String name, boolean resolve)
a:参数name代表类的全限定类名
b:参数resolve代表是否解析,resolve为true是解析该类
Class.forName(String name)
其实该方法内部调用的是:Class.forName(className, true, ClassLoader.getClassLoader(caller))
方法:Class.forName0(String name, boolean initialize, ClassLoader loader)
参数name代表全限定类名
参数initialize表示是否初始化该类,为true是初始化该类
参数loader 对应的类加载器
两者最大的区别
- Class.forName除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。也会加载静态方法。
- classloader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
- Class.forName(name,initialize,loader)带参数也可控制是否加载static块。并且只有调用了newInstance()方法才执行构造函数,创建类的对象。
package com.kuang;
public class ClassloaderAndForNameTest {
public static void main(String[] args) {
String wholeNameLine = "com.kuang.Line";
String wholeNamePoint = "com.kuang.Point";
System.out.println("下面是测试Classloader的效果");
testClassloader(wholeNameLine, wholeNamePoint);
System.out.println();
System.out.println("下面是测试Class.forName的效果");
testForName(wholeNameLine, wholeNamePoint);
}/**
* classloader
* @param wholeNameLine
* @param wholeNamePoint
*/
private static void testClassloader(String wholeNameLine, String wholeNamePoint) {
Class> line;
Class> point;
ClassLoader loader = ClassLoader.getSystemClassLoader();
try {
line = loader.loadClass(wholeNameLine);
point = loader.loadClass(wholeNamePoint);
System.out.println("line " + line.getName());
System.out.println("point " + point.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}/**
* Class.forName
* @param wholeNameLine
* @param wholeNamePoint
*/
private static void testForName(String wholeNameLine, String wholeNamePoint) {
try {
Class> line = Class.forName(wholeNameLine);
Class> point = Class.forName(wholeNamePoint);
System.out.println("line" + line.getName());
System.out.println("point" + point.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}}
}class Point {
static {
System.out.println("静态代码块执行: loading point");
}
public static String s = getString();
private static String getString() {
System.out.println("静态方法执行给静态变量赋值:loading point");
return "mask";
}public static void test() {
System.out.println("普通静态方法执行:loading point");
}{
System.out.println("point普通代码块");
}public Point() {
System.out.println("point构造方法执行");
}
}
class Line {
static {
System.out.println("静态代码块执行: loading line");
}public static String s = getString();
private static String getString() {
System.out.println("给静态变量赋值的静态方法执行:loading line");
return "mask";
}public static void test() {
System.out.println("普通静态方法执行:loading line");
}{
System.out.println("普通代码块");
}public Line() {
System.out.println("构造方法执行");
}}//输出结果:
//下面是测试Classloader的效果
//line com.kuang.Line
//point com.kuang.Point
//
//下面是测试Class.forName的效果
//静态代码块执行: loading line
//给静态变量赋值的静态方法执行:loading line
//静态代码块执行: loading point
//静态方法执行给静态变量赋值:loading point
//linecom.kuang.Line
//pointcom.kuang.Point
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 为什么你的路演总会超时()
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- thinkphp|thinkphp 3.2 如何调用第三方类库
- 使用composer自动加载类文件
- 一个健康的APP和健全的人格大体类似
- 种树郭橐驼传(文言句式+古今异义+词类活用+通假字)
- 归乡-序章(世界伊始,人类无所依靠,我的故事就从这里开始...)
- jQuery插件
- java简介|Java是什么(Java能用来干什么?)