java基础

1. @Override

@Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处: 1、可以当注释用,方便阅读; 2、编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错。例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。 举例:在重写父类的onCreate时,在方法前面加上@Override 系统可以帮你检查方法的正确性。 @Override public void onCreate(Bundle savedInstanceState)
{…….} 这种写法是正确的,如果你写成:
@Override public void oncreate(Bundle savedInstanceState)
{…….} 编译器会报如下错误:The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以确保你正确重写onCreate方法(因为oncreate应该为onCreate)。而如果你不加@Override,则编译器将不会检测出错误,而是会认为你为子类定义了一个新方法:oncreate

2. # [java中Class对象详解和类名.class, class.forName(), getClass()区别]https://www.cnblogs.com/Seachal/p/5371733.html

Java反射学习

所谓反射,可以理解为在运行时期获取对象类型信息的操作。传统的编程方法要求程序员在编译阶段决定使用的类型,但是在反射的帮助下,编程人员可以动态获取这些信息,从而编写更加具有可移植性的代码。严格地说,反射并非编程语言的特性,因为在任何一种语言都可以实现反射机制,但是如果编程语言本身支持反射,那么反射的实现就会方便很多。

1,获得类型类

我们知道在Java中一切都是对象,我们一般所使用的对象都直接或间接继承自Object类。Object类中包含一个方法名叫getClass,利用这个方法就可以获得一个实例的类型类。类型类指的是代表一个类型的类,因为一切皆是对象,类型也不例外,在Java使用类型类来表示一个类型。所有的类型类都是Class类的实例。例如,有如下一段代码

A a = new A();  
  
if(a.getClass()==A.class) {  
  
      System.out.println("equal");  
  
} else {  
  
      System.out.println("unequal");  
  
}  
输出equal;  

*可以看到,对象a是A的一个实例,A是某一个类,在if语句中使用a.getClass()返回的结果正是类A的类型类,在Java中表示一个特定类型的类型类可以用“类型.class”的方式获得,因为a.getClass()获得是A的类型类,也就是A.class,因此上面的代码执行的结果就是打印出“equal”。特别注意的是,类型类是一一对应的,父类的类型类和子类的类型类是不同的,因此,假设A是B的子类,那么如下的代码将得到“unequal”的输出:

A a = new A();  
  
if(a.getClass()==B.class) {  
  
        System.out.println("equal");  
  
}  else {  
          
          System.out.println("unequal");  
}  
输出unequal; 

2,获得类型的信息

在获得类型类之后,你就可以调用其中的一些方法获得类型的信息了,主要的方法有:

getName():String:获得该类型的全称名称。

getSuperClass():Class:获得该类型的直接父类,如果该类型没有直接父类,那么返回null。

getInterfaces():Class[]:获得该类型实现的所有接口。

isArray():boolean:判断该类型是否是数组。

isEnum():boolean:判断该类型是否是枚举类型。

isInterface():boolean:判断该类型是否是接口。

isPrimitive():boolean:判断该类型是否是基本类型,即是否是int,boolean,double等等。

isAssignableFrom(Classcls):boolean:判断这个类型是否是类型cls的父(祖先)类或父(祖先)接口。

getComponentType():Class:如果该类型是一个数组,那么返回该数组的组件类型。

此外还可以进行类型转换这类的操作,主要方法有:

asSubclass(Class clazz):Class:将这个类型


在学习反射时想到了这个问题,.getClass()和.class有没有什么区别?
当然,最明显的区别就是.getClass()是一个对象实例的方法,只有对象实例才有这个方法,具体的类是没有的。类的Class类实例是通过.class获得的,显然,类没有.getClass()方法。
从网上还找到一些其他资料:
1、出现的时期不同:Class.forName()在运行时加载;Class.class和getClass()是在编译时加载.

这里有些个疑问?Class.forName("XXX")这方法是动态加载class,先把类文件加载进来,再使用.newInstance()时创建了一个对象。

new ClassName(),就是所谓的静态加载,
Class.forName("ClassName"),就是所谓的动态加载。
区别在于“静态加载”的类在编译的时候就要提供,而动态加载的类在源程序编译时可以缺席,在运行时按需提供。

Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段
2、 举个例子,Iterator it = s.iterator();得到的it的真正类型是KeyIterator,是Iterator的子类,按常理来说应该可以执行next()方法,但是值 得注意的是,KeyIterator是hashmap的内部类,JAVA给的提示是cannot access a member of class java.util.HashMap$KeyIterator withmodifiers "public"
从上面的那些例子上也能看出,除内部类外的其他类的应用上.class功能完全等于.getClass()!只是一个是用类直接获得的,一个是用实例获得的。


Class对象的生成方式如下:

1.类名.class 说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象

2.Class.forName("类名字符串") (注:类名字符串是包名+类名) 说明:装入类,并做类的静态初始化,返回Class的对象

3.实例对象.getClass() 说明:对类进行静态初始化、非静态初始化;返回引用运行时真正所指的对象(因为:子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象

通过下面的程序,来观察一下Class对象的生成的原理。

[java] view plaincopy

[图片上传失败...(image-818d2b-1538236941380)]

  1. package ClassTest;

  2. public class TestClass {

  3. public static void main(String[] args) {

  4. try {

  5. // 测试.class

  6. @SuppressWarnings("rawtypes")

  7. Class testTypeClass = TestClassType.class;

  8. System.out.println("testTypeClass---" + testTypeClass);

  9. // 测试Class.forName()

  10. @SuppressWarnings("rawtypes")

  11. Class testTypeForName = Class.forName("ClassTest.TestClassType");

  12. System.out.println("testTypeForName---" + testTypeForName);

  13. // 测试Object.getClass()

  14. TestClassType testTypeGetClass = new TestClassType();

  15. System.out.println("testTypeGetClass---"

    • testTypeGetClass.getClass());
  16. } catch (ClassNotFoundException e) {

  17. // TODO Auto-generated catch block

  18. e.printStackTrace();

  19. }

  20. }

  21. }

[java] view plaincopy

[图片上传失败...(image-99b2e9-1538236941380)]

  1. package ClassTest;

  2. public class TestClassType {

  3. // 构造函数

  4. public TestClassType() {

  5. System.out.println("----构造函数---");

  6. }

  7. // 静态的参数初始化

  8. static {

  9. System.out.println("---静态的参数初始化---");

  10. }

  11. // 非静态的参数初始化

  12. {

  13. System.out.println("----非静态的参数初始化---");

  14. }

  15. }

运行结果如下

[java] view plaincopy

[图片上传失败...(image-167b6e-1538236941380)]

  1. testTypeClass---class ClassTest.TestClassType
  2. ---静态的参数初始化---
  3. testTypeForName---class ClassTest.TestClassType
  4. ----非静态的参数初始化---
  5. ----构造函数---
  6. testTypeGetClass---class ClassTest.TestClassType

** 然而单独执行 ****测试Class.forName() 时结果为**

---静态的参数初始化e---
testTypeForName---测试Class.forName()/class ClassTest.TestClassType

单独执行****测试Object.getClass() 结果为

---静态的参数初始化e---
----非静态的参数初始化e---
----构造函数e---
testTypeGetClass---测试Object.getClass()/class ClassTest.TestClassType

所以根据结果可以发现,三种生成的Class对象一样的。并且程序只打印一次“静态的参数初始化”,但时拆分单独执行时class.forName(),Object.getClass()时

都执行了“静态的参数初始化”。

我们知道,静态的方法属性初始化,是在加载类的时候初始化。而非静态方法属性初始化,是new 类实例对象的时候加载。

因此,这段程序说明,三种方式生成Class对象,其实只有一个Class对象。在生成Class对象的时候,首先判断内存中是否已经加载。

所以,生成Class对象的过程其实是如此的:

当我们编写一个新的java类时,JVM就会帮我们编译成class对象,存放在同名的.class文件中。在运行时,当需要生成这个类的对象,JVM就会检查此类是否已经装载内存中。若是没有装载,则把.class文件装入到内存中。若是装载,则根据class文件生成实例对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一:java概述: 1,JDK:Java Development Kit,java的开发和运行环境,java的开发...
    慕容小伟阅读 1,849评论 0 10
  • 1.JAVA中的几种基本数据类型是什么,各自占用多少字节。答:int 32bitshort 16bit...
    随风_dong阅读 2,162评论 6 8
  • 什么是反射 反射是一个很牛的功能,能够在程序运行时修改程序的行为。但是反射是非常规手段,反射有风险,应用需谨慎。把...
    dashingqi阅读 630评论 0 1
  • 一、类的加载 (一) 定义及过程: 当程序需要使用某个类的时候,如果这个类还没有被加载到内存中,则系统会通过加载、...
    VictorBXv阅读 327评论 0 2
  • JAVA基础 基本类型 enum 枚举Size { SMALL , MEDIUM , LARGE , EXTRA ...
    荡轻风阅读 424评论 0 0