how2j.cn


工具版本兼容问题
类对象概念: 所有的类,都存在一个类对象,这个类对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法。


7分13秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)

步骤 1 : 什么是类对象   
步骤 2 : 获取类对象   
步骤 3 : 获取类对象的时候,会导致类属性被初始化   
步骤 4 : 练习-在静态方法上加synchronized,同步对象是什么?   
步骤 5 : 答案-在静态方法上加synchronized,同步对象是什么?   

步骤 1 :

什么是类对象

在理解类对象之前,先说我们熟悉的对象之间的区别:
garen和teemo都是Hero对象,他们的区别在于,各自有不同的名称,血量,伤害值

然后说说类之间的区别
Hero和Item都是类,他们的区别在于有不同的方法,不同的属性

类对象,就是用于描述这种类,都有什么属性,什么方法的
步骤 2 :

获取类对象

获取类对象有3种方式
1. Class.forName
2. Hero.class
3. new Hero().getClass()

在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。

注: 准确的讲是一个ClassLoader下,一种类,只会有一个类对象存在。通常一个JVM下,只会有一个ClassLoader。因为还没有引入ClassLoader概念, 所以暂时不展开了。
package reflection; import charactor.Hero; public class TestReflection { public static void main(String[] args) { String className = "charactor.Hero"; try { Class pClass1=Class.forName(className); Class pClass2=Hero.class; Class pClass3=new Hero().getClass(); System.out.println(pClass1==pClass2); System.out.println(pClass1==pClass3); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package reflection;

import charactor.Hero;

public class TestReflection {

	public static void main(String[] args) {
			String className = "charactor.Hero";
			try {
				Class pClass1=Class.forName(className);
				Class pClass2=Hero.class;
				Class pClass3=new Hero().getClass();
				System.out.println(pClass1==pClass2);
				System.out.println(pClass1==pClass3);
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
}
步骤 3 :

获取类对象的时候,会导致类属性被初始化

为Hero增加一个静态属性,并且在静态初始化块里进行初始化,参考 类属性初始化

static String copyright;
static {
System.out.println("初始化 copyright");
copyright = "版权由Riot Games公司所有";
}

无论什么途径获取类对象,都会导致静态属性被初始化,而且只会执行一次。(除了直接使用 Class c = Hero.class 这种方式,这种方式不会导致静态属性被初始化)
获取类对象的时候,会导致类属性被初始化
package charactor; public class Hero { public String name; public float hp; public int damage; public int id; static String copyright; static { System.out.println("初始化 copyright"); copyright = "版权由Riot Games公司所有"; } }
package reflection; import charactor.Hero; public class TestReflection { public static void main(String[] args) { String className = "charactor.Hero"; try { Class pClass1=Class.forName(className); Class pClass2=Hero.class; Class pClass3=new Hero().getClass(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
步骤 4 :

练习-在静态方法上加synchronized,同步对象是什么?

Or  姿势不对,事倍功半! 点击查看做练习的正确姿势
在之前有一个练习,练习-在类前面加修饰符synchronized

在对象方法前,加上修饰符synchronized ,同步对象是当前实例。
那么如果在类方法前,加上修饰符 synchronized,同步对象是什么呢?

编写代码进行验证
步骤 5 :

答案-在静态方法上加synchronized,同步对象是什么?

在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
当synchronized修饰静态方法的时候, 同步对象就是这个类的类对象。

如代码中的例子,当第一个线程进入method1的时候,需要占用TestReflection.class才能执行。

第二个线程进入method2的时候进去不,只有等第一个线程释放了对TestReflection.class的占用,才能够执行。 反推过来,第二个线程也是需要占用TestReflection.class。 那么TestReflection.class就是method2的同步对象。

换句话说,静态方法被修饰为synchronized的时候,其同步对象就是当前类的类对象。
package reflection; public class TestReflection { public static void main(String[] args) throws InterruptedException { Thread t1= new Thread(){ public void run(){ //调用method1 TestReflection.method1(); } }; t1.setName("第一个线程"); t1.start(); //保证第一个线程先调用method1 Thread.sleep(1000); Thread t2= new Thread(){ public void run(){ //调用method2 TestReflection.method2(); } }; t2.setName("第二个线程"); t2.start(); } public static void method1() { synchronized (TestReflection.class) { // 对于method1而言,同步对象是TestReflection.class,只有占用TestReflection.class才可以执行到这里 System.out.println(Thread.currentThread().getName() + " 进入了method1方法"); try { System.out.println("运行5秒"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static synchronized void method2() { // 对于mehotd2而言,必然有个同步对象,通过观察发现,当某个线程在method1中,占用了TestReflection.class之后 // 就无法进入method2,推断出,method2的同步对象,就是TestReflection.class System.out.println(Thread.currentThread().getName() + " 进入了method2方法"); try { System.out.println("运行5秒"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }


HOW2J公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2018-05-05 请问基本类型如int, float有类对象吗
Duankang
请问基本类型如int, float有类对象吗?试了一下int.class行得通。具体怎么解释?




3 个答案

探索 答案时间:2018-06-09
都是取Class的引用的,但是取得是不同的Class的引用。 Interger.TYPE == int.class 是基本类型int的Class的引用,int是基本类型在虚拟机运行时就已经加载了他的Class. Interger.class 是int的封装类Interger的引用。 因此二者是不同的。
基本数据类型的 .class 都 ==  包装类型 .TYPE

探索 答案时间:2018-06-09
他们可以自动装拆箱 就是自动进行转换

探索 答案时间:2018-06-09
int的类对象 是Integer float的类对象为 Float char 为 Character 这个叫做包装类(封装类)




答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到




2017-12-25 加包名 与不加 为什么类对象不一样
CHXYMJR



Hero对象同在package Test 下,加包名类对象是一样的,不加包名类对象为什么不用啊?老师
package Test;

 
public class test {
 
    public static void main(String[] args) {
            String className = "Hero";
            try {
                Class pClass1=Class.forName(className);
                Class pClass2=Hero.class;
                Class pClass3=new Hero().getClass();
                System.out.println(pClass1);
                System.out.println(pClass2);
                System.out.println(pClass3);
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }
}
初始化 copyright
class Hero
class Test.Hero
class Test.Hero


1 个答案

ewqddsad 答案时间:2018-01-10
Class.forName(className); 这个方法需要使用完整类名,也就是包名加上类的名称,其实 类名就是 包名加上类的名称才叫类名 咱们平时使用的类名 没有写包名是因为使用到import 进行了导包,可以理解成一种简写形式。




答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2017-12-09 练习的最后一个问题
2017-11-07 使用.class不会初始化Class对象
2017-08-28 如何获取同一个包的类对象
2017-07-04 dwre
2017-07-04 dgftryh
2016-06-30 .getName() 改成,name吧




提问之前请登陆
关于 JAVA 高级-反射机制-获取类对象 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 620943819
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: http://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图