Java中关于先有鸡还是先有蛋的问题----Class&Object

在Java中,我们常常会看到一个类型:Class。并且在类似Person.class,cache.getClass()等代码中见到它的身影。

众所周知,Class是用来描述一个类的类型,而Object是所有对象的最终父对象。那么就会引申出下边的两个结论:

1、如果从对象的角度来看,那么肯定是先有Object对象,其次才有其派生的对象Class。

2、Class表示的是类、对象,肯定是先有类这个概念,其次才有各个类型(抽象的、非抽象的),包括Object。

这就会出现一个问题,到底是先有Class(鸡)还是先有Object(蛋)?

好吧,此处先给出答案,是先有Object,然后才有Class的。

原因是Object,是所有对象的最终父对象,而Class本身也是一个对象。所以是先有Object,然后才Class对象的。

那么如何解释第二点呢? 这是因为一个概念被混淆了。

在Java中,所有的对象都派生自Object,而Class类(注意此处是大写也是一个类)所以他也继承自Object,这个我们可以在eclipse里边通过查看类的继承关系清楚的看到。

在Java中,还有一个class(注意此处是小写)。他表示的是一个个(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )对象,也就是一个个类。Object是这些对象的其中之一。同时在这些对象中有一个对象,它的作用是用来识别标记其它对象的内容,这个类叫做Class(注意此处是大写)。 因此就会出现有一个class的名字叫做Class。而问题中将class等价于Class,很显然是不合理的。两者完全不在一个维度里。

所以这样就可以很好的理解,JVM在启动后,会加载各个需要的class,其中包括Class。

抛砖引玉----深入学习Class类

了解了class,Object,Class的关系,我们接下来深入说说Class类。(这才是这篇博客的主要目的)

 一、背景知识

类对象在使用之前都会被JVM加载(其实是经过加载、连接、初始化三个步骤对类完成初始化)。类加载指的就是JVM将class文件读入内存,并为之创建一个Class对象。同时当一个类被加载后,再次使用时,就不会被重复加(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )载。这样新建的Class与加载的class就形成一一对应的关系。 通过该Class对象,就可以访问到对应的class。所以我们可以把Class理解为一个类的标识对象,它相当于是一个类的标签(铭牌)。拿到一个Class,我们就可以找到对应的类(class)。

二、获取Class对象的方法

在Java中我们可以使用三个方法拿到Class对象。其中两种是针对已经在家的类对象,去获得他对应的Class对象。剩余一种利用到了反射,根据提供的类名去寻找对应的class文件,进而找到Class对象。

1 Class.forName(String className)//className表示完整的名称,包括该类的包名。如果无法找到,该方法会抛出一个
2 Person.class //Person代表的是一个类,class字段是其默认的属性
3 person.getClass() //getClass是Obj类的一个实例方法,所有的类都有该方法,包括Class类 

三、 从Class中可以获取到的信息

系统可以通过Class对象,找到该对象对应的class.而Class对象包含了class的基本详细信息。这些信息可以分为以下四个方面: 1、获取到class所包含的构造器。 2、获取到class所包含的方法。 3、获取到class所包含的成员变量。 4、获取到class所包含的Annotation。 ps 很多小伙伴可能对Annotation不太熟悉,这里简单说下:Annotation翻译为注解,本身也是一个类,可以用来保存类的描述信息。 有兴趣的可以参考下面这篇文章:

http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html

四、在工作中Class类的使用用途

在这里我总结了一下曾经遇到的使用情况,将其分为;两方面,如果有遗漏,大家可以补充。

1、对对象类型的使用和校验

有些时候,我们需要对传入对象的类型进行校验,判断传入的对象是否为我们需要的类型。

if(para.getClass==Person.class)//如果这里使用 instance关键字,则可能会受到Person类继承关系的干扰,导致无法进行正确的判断。 

2、反射

<1>用字符串定义需要加载的类名,然后等到需要时候再加载。

  这样做有三个用途:

  (1)有时候并不知道此处需要加载的类型,需要在运行时才可能知道需要加载哪个class,譬如在运行的过程中,根据用户的手动设置,动态的选择接下来要加载的类。

  (2)在编译时已经知道需要加载的类名,但是尚无需要加载的.class文件,需要在运行时,通过用户上传,或者后台到指定地址下载class文件。   插件化开发的实现就是使用这样一个原理。举两个例子:

      (α)用户在使用过滤时,需要自己来定义一套复杂的过滤机制,这时可能就无法通过界面简单的设置一下需要过滤的内容。可以由用户手动的上传自己的过滤算法的jar包,然后由后台动态的加载,使用该算法。

      (β)亦或者有时候在工作环境中,对于皮肤显示有一套默认的显示效果,同时也支持用户自己上传需要显示效果的jar包。后台拿到用户上传的jar包后,反射出需要用到的特效算法,形成动态的交互。

  (3)缩短编译时间,加快启动软件的速度(包括client 和server)

  在启动时,包含main方法的类被加载,同时它会加载(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )所自己需要的类。这些类再一次加载自己所需要的类。形成递推关系。但是对一个大应用程序来说,整个的启动(加载)过程耗费的时间,常常让用户无法忍受,甚至在还未加载完时就被强制关闭了。

  针对这种情况,我们就可以在mian方法类中加载一些最基本的类。诸如登录、验证等。当登录验证没有问题之后,需要进入业务操作时,才会根据用户的选择,   加载用户需要的类。从而提高软件整体的运行效率和用户体验。

<2>对于工具的开发和使用

当我们开发工具或脚本时,除了使用系统公开的API外,有时还需要用到原有代码中被私有化的一些变量和方法。这时仅仅使用继承是不够的,还需要反射出对象,拿到其中的变量或调用其中的方法。 比如平常使用的UT框架,有时为了测试效率,就提供了很多可以直接调用待测试类私有方法的API。

时间: 2024-10-16 05:42:40

Java中关于先有鸡还是先有蛋的问题----Class&Object的相关文章

Java中的代理

代理模式 在设计模式中存在的代理模式;代理模式的作用就是为其他对象提供一种代理以控制对这个对象的访问. 代理模式一般存在三种角色:抽象角色,代理角色,真实角色:百度百科上摘抄了三种角色的解释: 抽象角色:通过接口或抽象类声明真实角色实现的业务方法. 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作. 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用. 代理模式的优点:一是可以隐藏委托类(真实角色)的实现,二是可以实现客

Java中泛型的介绍与简单使用

学习目标 掌握泛型的产生意义. 掌握泛型的基本使用. 了解泛型的警告信息及泛型的擦除. 泛型是在JDK1.5之后增加的内容,泛型(Generic) 使用泛型的原因 题目分析: 首先要考虑到,必须建立一好一个表示坐标点的类--Point,此类中有两个属性分别用来表示x坐标和y坐标,但是x和y中所保存的整数类型会有三种(int.float.String),而要想使用一个类型可以同时接收这样的三种类型数据,现在只能使用Object,因为Object类可以接收任何类型的数据,都会自动发生向上转型操作,这

java中几个小遗漏

1.首先 Scanner sn=new Scanner(System.in); int i=sn.nextInt();  String ss=sn.next();没有空格的  String sss=sn.nextLine();有空格可以 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Java中对比两个对象中属性值[反射、注解]

在Java中通常要比较两个对象在修改前与修改后的值是否相同,一般我们采用的是反射技术获取对象的get方法[或其他的方法]获取值并做比较.如果系统将修改的属性名称也显示出来,这样就能更直观的显示类中的哪一个属性的值被修改了.然后Java中只能获取属性的名称,也就是英文标识的属性名,但是一般我们都会在属性后面添加属性的注释,但是Java不提供注释获取的方法.所以我们只能使用另外一种方式来将属性和属性注释关联起来,这就是Java中的@Annotation. public static  Map<Str

浅谈利用同步机制解决Java中的线程安全问题

我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等着前面千百万人挑选购买,最后心仪的商品下架或者售空......假如饿了吗是单线程程序,那么一个用户得等前面全国千万个用户点完之后才能进行点餐,那饿了吗就该倒闭了不是吗?以上两个简单的例子,就说明一个程序能进行多线程并发访问的重要性,今天就让我们去了解一下Java中多线程并发访问这个方向吧. **第一

Java中的线程

理解线程 这段时间在看<Java并发编程实战>这本书,使自己对Java多线程的理解又加深一些,感觉自己可以总结一下了,本文就讲讲与线程有关的内容吧.我们要使用线程,首先需要理解线程,前短时间我在聊聊操作系统这篇文章中提到了一点关于线程的东西,有兴趣的同学可以读一下.有一点需要理解的就是,我们虽然常说"Java多线程",但实际上线程这东西是由操作系统提供支持的,它并不是由Java本身提供支持的,所以实际上线程的实现是平台相关的!看过Object类源码的同学应该都能注意到,Ob

java 中的字符串处理--正则表达式

最近在做一些支付报文处理工作,需要从各种各样的报文中提取需要的信息比如(金额,订单号...),每个渠道报文各式各样,想要写一个通用的提取逻辑,于是就回顾java正则表达式的用法.当然我们可以自己写一些算法,去提取这些字段,但对于简单的解析来说,亲自手写算法有点杀鸡用牛刀的感觉,而且正则表达式完全可以满足大部分的字符提取需求.好了闲话不多说,先列出正则表达式的常用语法: \:表示下一个字符为特殊含义的字符例如:\d匹配数字 ^:表示匹配字符开始的位置例如:^#.*:匹配以#开头的所有字符 $:表示

java中的三元运算符详解

最近在带领实习生中遇到很多新手问与三元运算符有关的java题目,多数为代码结果题,少数为应用题.鉴于很多资料上对于java三元运算的讲解过于简单,网上的资料与题目也不是很完善,对于结果答案分析不一,故在此总结,当然仅为个人观点,水平有限,不足之处,还请大家多多指出,互相交流学习. 什么是java三元运算符呢?无疑其操作元有三个,第一个是条件表达式,剩余两个为值,条件表达式为真时运算取第一个值,为假时取第二个值. 其示例代码如下:boolean a = 20 < 45 ? true : false

java中BigDecimal的学习

干着java的活,但是看的都是一些偏底层的东西(或者我根本就没有看),有点荒废了java的学习. 最近一直在用到一个类是BigDecimal,但都是模棱两可地在那儿用,并没有深入研究这个类的细节,感觉不能再拖了. BigDecimal,从名字来看就是进行大数运算的,不光这样,还广泛用于小数的精确运算. 当你接触到和钱有关的计算的时候,这个类还是很有用滴. 先来看一个例子 1 package com.tuhooo.bigdecimal; 2 3 /** 4 * Created by tuhooo