「面试复习」「Java」一、Java基础

目录

(一)Java基础知识点

1)面向对象的特性有哪些?

2)面向对象和面向过程的区别?

3)Java 中覆盖和重载是什么意思?

4)抽象类和接口的区别有哪些?

5)“static” 关键字是什么意思?

6)Integer 的缓存机制

7)下述两种方法分别创建了几个 Sring 对象?

8)String、StringBuffer、StringBuilder的区别?

9)equals()方法和 “==” 运算符和hashCode()方法区别?

10)Java 对象初始化顺序?

11)exception 和 error 有什么区别?

12)throw 和 throws 有什么区别?

13)单例模式?

(二)Java反射

1)什么是反射?

2)反射的理解?

3)反射的用途?

4)反射的好处?

5)反射的使用?

参考:


(一)Java基础知识点

1)面向对象的特性有哪些?

封装、继承和多态(应要多算一个那就是抽象)

  • 封装:指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
    但封装不仅仅是 private + getter/setter ,使用封装可以对 setter 进行更深层次的定制,例如你可以对执行方法的对象做规定,也可以对数据做一定的要求,还可以做类型转换等等。使用封装不仅仅安全,更可以简化操作。(封装扩展阅读:oc面向对象三大特性之一 <封装>

    访问控制级别表:
     
     
    private
    default
    protected
    public
    同一个类中
    ☑️
    ☑️
    ☑️
    ☑️
    同一个包中
     
    ☑️
    ☑️
    ☑️
    子类中
     
     
    ☑️
    ☑️
    全局范围内
     
     
     
    ☑️
  • 继承:实现软件复用的重要手段。子类是对父类的拓展,子类是特殊的父类。
    继承的缺点:1)继承是一种强耦合关系,父类变子类也必须变;2)继承破坏了封装,对于父类而言,它的实现细节对子类来说都是透明的。

  • 多态:Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型来决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就有可能出现多态。简而言之就是,相同类型的变量,调用同一个方法时呈现出不同的行为特征。

    (比如说,有一杯水,我不知道它是温的、冰的还是烫的,但是我一摸我就知道了,我摸水杯的这个动作,对于不同温度的水,就会得到不同的结果,这就是多态。)
    多态的条件1)继承;2)重写;3)向上转型。

    多态的好处:当把不同的子类对象都当作父类类型来看,可以屏蔽不同子类对象之间的实现差异,从而写出通用的代码达到通用编程,以适应需求的不断变化。(多态扩展阅读:重新认识java(五) ---- 面向对象之多态(向上转型与向下转型)

    Father ins = new Son();
    ins.function();
    Ins只能调用Father(编译时类型)的方法,但运行时实际执行的是Son(运行时类型)的方法。
  • 抽象是指从特定的角度出发,从已经存在的一些事物中抽取我们所关注的特性、行为,从而形成一个新的事物的思维过程,是一种从复杂到简洁的思维方式。

2)面向对象和面向过程的区别?

面向过程是一种站在过程的角度思考问题的思想,强调的是功能行为,功能的执行过程,即先干啥,后干啥。

  • 面向过程的设计,是采用置顶而下的设计方式,在设计阶段就需要考虑每一个模块应该分解成哪些子模块,每一个子模块有细分为更小的子模块,如此类推,直到将模块细化为一个个函数。
  • 问题:1)设计不够直观,与人类的习惯思维不一致;2)系统软件适应性差,可扩展性差,维护性低。

面向对象是一种基于面向过程的新的编程思想,是一种站在对象的角度思考问题的思想,我们把多个功能合理的放到不同对象里。

  • 面向对象更加符合我们常规的思维方式,稳定性好,可重用性强,易于开发大型软件产品,有良好的可维护性。在软件工程上,面向对象可以使工程更加模块化,实现更低的耦合和更高的内聚。
  • 注意: 不要粗浅的认为面向对象一定就优于面向过程的设计

扩展阅读:面向过程 VS 面向对象

3)Java 中覆盖和重载是什么意思?

覆盖(Override)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小,被覆盖的方法不能是 private 的,否则只是在子类中重新定义了一个新方法。

重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。

构成重载的条件有哪些?

答:参数类型不同、参数个数不同、参数顺序不同。

函数的返回值不同可以构成重载吗?为什么?

答:不可以,因为 Java 中调用函数并不需要强制赋值。

4)抽象类和接口的区别有哪些?

接口:接口作为系统与外界交互的窗口,体现的是一种规范。

对于接口的实现者而言,接口规定了实现者必须向外提供哪些服务(以方法的方式提供);对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务(就是如何来调用方法)。

当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准。

接口类似于整个系统的“总纲”,制定了系统各个模块应该遵循的标准。

抽象类:抽象类作为系统中多个子类的共同父类,它所体现的是一种模版式设计。

抽象类作为多个子类的抽象父类,可以被当作是系统实现过程中的中间产品,这个中间产品已经实现了系统的部分功能(那些已经提供实现的方法),但这个产品依然不能当成最终产品,必须有更进一步的完善,这种完善可能有几种不同的形式。

都不能被实例化,都位于继承树的顶端,用于被其他类实现和继承。

都包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。

 
接口
抽象类
方法
只能包含抽象方法、静态方法、默认方法,不能为普通方法提供方法实现
完全可以包含普通方法
变量
只能定义静态常量,不能定义普通成员变量
既可以定义普通成员变量,也可以定义静态常量
构造器
不能包含构造器
可以包含构造器,抽象类中的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作
初始化块
不能包含初始化块
完全可以包含初始化块
继承与实现
一个类可以直接实现多个接口
一个类只能有一个父类,包括抽象类

抽象类和接口如何选择

答:

  1. 考虑你需要设计的是一种规范,还是一种模板。

  2. 如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。

  3. 如果知道某个类应该是基类,那么只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

5)“static” 关键字是什么意思?

static” 关键字表明一个成员变量或者是成员方法是属于类而非属于对象的,可以在没有所属的类的实例变量的情况下被访问。

Java中是否可以覆盖(override)一个 private 或者是 static 的方法?

答:Java 中 static 方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而 static 方法编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。

Java 中也不可以覆盖 private 的方法,因为 private 修饰的变量和方法只能在当前类中使用,如果是其他的类继承当前类是不能访问到 private 变量或方法的,当然也不能覆盖。

扩展阅读:重新认识java(六) ---- java中的另类:static关键字(附代码块知识)

6)Integer 的缓存机制

Integer 有缓存机制,在 JVM 启动初期就缓存了 -128 到 127 这个区间内的所有数字。

7)下述两种方法分别创建了几个 Sring 对象?

// 第一种:直接赋一个字面量
String str1 = "ABCD";
// 第二种:通过构造器创建
String str2 = new String("ABCD");

String str1 = "ABCD";最多创建一个String对象,最少不创建String对象。如果常量池中,存在”ABCD”,那么str1直接引用,此时不创建String对象。否则,先在常量池先创建”ABCD”内存空间,再引用。

String str2 = new String("ABCD");最多创建两个String对象,至少创建一个String对象。new关键字绝对会在堆空间创建一块新的内存区域,所以至少创建一个String对象。

  • 当执行第一句话的时候,会在常量池中添加一个新的ABCD字符,str1指向常量池的ABCD
  • 当执行第二句话的时候,因为有new操作符,所以会在堆空间新开辟一块空间用来存储新的String对象,因为此时常量池中已经有了ABCD字符,所以堆中的String对象指向常量池中的ABCD,而str2则指向堆空间中的String对象。

String 对象是一个特殊的存在,需要注意的知识点也比较多,这里给一个之前写的 String 详解的文章链接:传送门 其中包含的问题大概有:1)“+” 怎么连接字符串;2)字符串的比较;3)StringBuilder/StringBuffer/String 的区别;

8)String、StringBuffer、StringBuilder的区别?

1. 可变不可变

String中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。

private final char value[];

StringBuilderStringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。

char[] value;

2. 是否线程安全

String中的对象是不可变的,也就可以理解为常量,显然线程安全

AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。

StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。看如下源码:

public synchronized StringBuffer reverse() {
    super.reverse();
    return this;
}

StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

3. StringBuilderStringBuffer共同点

StringBuilder与StringBuffer有公共父类AbstractStringBuilder(抽象类)

抽象类与接口的其中一个区别是:抽象类中可以定义一些子类的公共方法,子类只需要增加新的功能,不需要重复写已经存在的方法;而接口中只是对方法的申明和常量的定义。

StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(...)。只是StringBuffer会在方法上加synchronized关键字,进行同步。

最后,如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。

9)equals()方法和 “==” 运算符和hashCode()方法区别?

equals()方法,该方法主要用于比较两个对象是否相等。以下为源码:

public boolean equals(Object obj) {
    return (this == obj);
}

所有的对象都拥有标识(内存地址)状态(数据)。“==”比较两个对象的的内存地址,所以说Object的equals()方法就是比较两个对象的内存地址是否相等。实际上,String、Math等封装类都对equals()方法进行了重写

1. 对于字符串变量来说,使用“==”“equals()”方法比较字符串时,其比较方法不同

  • “==”比较两个变量本身的值,即两个对象在内存中的首地址
  • “equals()”比较字符串中所包含的内容是否相同。

2. 对于非字符串变量来说,"==""equals"方法的作用是相同的都是用来比较其对象在堆内存的首地址,即用来比较两个引用变量是否指向同一个对象
总之:

  • “equals()”方法对于字符串来说是比较内容的,而对于非字符串来说是比较其指向的对象是否相同的。
  • “==”是比较指向的对象是否相同的也就是对象在对内存中的的首地址

Java对象的eqauls方法hashCode方法是这样规定的:

  • 相等(相同)的对象必须具有相等的哈希码(或者散列码)。
  • 如果两个对象的hashCode相同,它们并不一定相同。

10)Java 对象初始化顺序?

不考虑静态成员的初始化,调用一个对象的构造函数时,程序1)先调用父类的构造函数(可以通过super关键字指定父类的构造函数,否则默认调用无参的构造函数,并且需要在子类的构造函数的第一行调用);2)之后静态成员变量的初始化函数和静态初始化块则按照在代码当中的顺序执行,成员变量如果没有指定值的话则赋予默认值,即基本数据类型为0或false等,对象则为null;3)最后调用自身构造函数。

11)exception 和 error 有什么区别?

Exception 和 Error 都是继承了 Throwable 类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。
Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类。
Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
Error 是指在正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如OutOfMemoryError之类,都是Error的子类。

Exception 又分为可检查(checked)异常不检查(unchecked)异常
可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。前面我介绍的不可查的 Error,是 Throwable 不是 Exception。
不检查异常就是所谓的运行时异常,类似 NullPointerException、ArrayIndexOutOfBoundsException 之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

有哪些Error、Exception 或者 RuntimeException?

12)throw 和 throws 有什么区别?

throw 关键字用来在程序中明确的抛出异常,相反,throws 语句用来表明方法不能处理的异常。每一个方法都必须要指定哪些异常不能处理,所以方法的调用者才能够确保处理可能发生的异常,多个异常是用逗号分隔的。

13)单例模式?

 1、懒汉式,线程不安全

描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
     }  
}  

这段代码简单明了,而且使用了懒加载( lazy loading )模式,但是却存在致命的问题。当有多个线程并行调用 getInstance() 的时候,就会创建多个实例。也就是说在多线程下不能正常工作。

2、懒汉式,线程安全

为了解决上面的问题,最简单的方法是将整个 getInstance() 方法设为同步(synchronized)。

描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
} 

虽然做到了线程安全,并且解决了多实例的问题,但是它并不高效。因为在任何时候只能有一个线程调用 getInstance() 方法。但是同步操作只需要在第一次调用时才被需要(即if语句中判断 instance 为null时才调用,不为null时是直接返回instance的),即第一次创建单例实例对象时。这就引出了双重检验锁。

3、双检锁/双重校验锁(DCL,即 double-checked locking)

双重检验锁模式(double checked locking pattern),是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。

描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。

public class Singleton {
    private volatile static Singleton singleton;//声明成 volatile
    private Singleton() {}

    public static Singleton getSingleton() {
        if (instance == null) {              // Single Checked
            synchronized (Singleton.class) {
                if (instance == null) {      // Double Checked
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}  

注意上面使用了volatile 关键字。

如果去掉volatile 关键字,它是有问题。主要在于instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。

  • 给 instance 分配内存
  • 调用 Singleton 的构造函数来初始化成员变量
  • 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)

但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。

所以我们只需要将 instance 变量声明成 volatile 就可以了。

4、饿汉式

饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。

描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。

它基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

这种写法如果完美的话,就没必要在啰嗦那么多双检锁的问题了。缺点是它不是一种懒加载模式(lazy initialization),单例会在加载类后一开始就被初始化,即使客户端没有调用 getInstance()方法。饿汉式的创建方式在一些场景中将无法使用:譬如 Singleton 实例的创建是依赖参数或者配置文件的,在 getInstance() 之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。

5、登记式/静态内部类

描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

这种方式同样利用了 classloder 机制来保证初始化 instance 时只有一个线程,它跟第 4 种方式不同的是:第 4 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有显示通过调用 getInstance 方法时,才会显示装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比第 4 种方式就显得很合理。

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}  

这种写法仍然使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。

(二)Java反射

1)什么是反射?

通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

Java 反射主要提供以下功能:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
  • 在运行时调用任意一个对象的方法

重点:是运行时而不是编译时

2)反射的理解?

3)反射的用途?

  • 使用 IDE(如 Eclipse,IDEA)时,当输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
  • 反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。

4)反射的好处?

更加灵活,降低耦合,提高代码的自适应能力。

不用反射:

public static void main(String[] args) {
    HeroFacrty facrty =new HeroFacrty();
    hero iroman= facrty.CreateHero("IronMan");
    iroman.attach();
}

public hero CreateHero(String name) {
    if ((name).equals("IronMan")) {
        return new IronMan();
    }
    if ((name).equals("Hulk")) {
        return new Hulk();
    }
    return null;
}

interface hero {
    public void attach();
}

class IronMan implements hero {

    @Override
    public void attach() {
        System.out.println("Laser Light");

    }
}

class Hulk implements hero {

    @Override
    public void attach() {
        System.out.println("fist");

    }
}

如果有成千上万个hero,那么过多的if判断就会显得非常冗余。

利用反射:

public static void main(String[] args) {
    HeroFacrty facrty = new HeroFacrty();
    Hero hero=facrty.CreateHero("test.IroMan");
    hero.attack();
}

public Hero CreateHero(String name) {
    try {
        Class<?> cls = Class.forName(name);
        Hero hero = (Hero) cls.newInstance();
        return hero;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}


interface Hero {
    public void attack();
}

class IroMan implements Hero {
    @Override
    public void attack() {
        System.out.println("Laser Light");

    }
}

class Hulk implements Hero {
    @Override
    public void attack() {
        System.out.println("Fist");

    }
}

利用反射机制进行解耦的原理就是利用反射机制“动态”的的创建对象:向CreateHero()方法传入Hero类的包名.类名,通过加载指定的类,然后再实例化对象。

5)反射的使用?

反射就是把Java类中的各种成分映射成一个个的Java对象。一个类有:构造方法、成员变量、成员方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

获取Class对象的方式:

  1. Object.getClass()
  2. 任何类(包括基本数据类型)都有一个“静态”的class属性
  3. 通过Class类的静态方法:Class.forName(String  className)(常用)
		//第一种方式获取Class对象  
		Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
		Class stuClass = stu1.getClass();//获取Class对象

		//第二种方式获取Class对象
		Class stuClass2 = Student.class;
		
		//第三种方式获取Class对象
		try {
			Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

获取对象的构造方法:

批量的:

  • public Constructor[] getConstructors():所有"公有的"构造方法
  • public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

单个的:

  • public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
  • public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有

调用构造方法:

  • Constructor-->newInstance(Object... initargs)
//加载Class对象
Class clazz = Class.forName("fanshe.Student");
		
//1
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
    System.out.println(c);
}
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
    System.out.println(c);
}
//2
Constructor con = clazz.getConstructor(null);
//调用构造方法
Object obj = con.newInstance();
		
con = clazz.getDeclaredConstructor(char.class);
//调用构造方法
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
obj = con.newInstance('男');

获取成员变量:

批量的:

  • Field[] getFields():获取所有的"公有字段"
  • Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;

单个的:

  • public Field getField(String fieldName):获取某个"公有的"字段;
  • public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)

设置字段的值:

  • Field --> public void set(Object obj,Object value):

参数:

1. obj:要设置的字段所在的对象;x

2. value:要为字段设置的值;

获取成员方法:

批量的:

  • public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
  • public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)

单个的:

  • public Method getMethod(String name,Class<?>... parameterTypes):
  • public Method getDeclaredMethod(String name,Class<?>... parameterTypes)

参数:
name : 方法名;
Class ... : 形参的Class类型对象

调用方法:

  • Method --> public Object invoke(Object obj,Object... args):

参数:
obj : 要调用方法的对象;
args:调用方式时所传递的实参;

 

 

 

参考:

https://www.jianshu.com/p/883260941da8

https://www.cnblogs.com/xudong-bupt/p/3961159.html

https://www.cnblogs.com/Qian123/p/5704007.html

https://www.cnblogs.com/Qian123/p/5703507.html

https://www.cnblogs.com/Qian123/p/5729172.html

https://www.sczyh30.com/posts/Java/java-reflection-1/

https://blog.csdn.net/sinat_38259539/article/details/71799078

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章