# Java 基础

Java面试题

# 实例化对象有哪些方式?

参考答案

  • ① 最常用的直接 new()的方式创建;
A a = new A();
  • ② 用clone方法创建, 需要类实现Cloneable 接口;
A a = (A)B.clone(); 
  • ③ 用Class.forName方法获取类,在调用类的newinstance()反射机制创建;
Class<?> cls = Class.forName("com.cn.A");
A a = (A)cls.newInstance();
  • ④ 用Objenesis,Objenesis是一个Java的库,主要用来创建特定的对象。即便没有空的构造函数也可以创建对象。
 Objenesis objenesis = new ObjenesisStd();
  A a = objenesis.newInstance(A.class);
  • ⑤ 使用 SpringObjenesis,这是Spring对Objenesis接口的一个实现。由Spring4.2之后提供的(ObjenesisCglibAopProxy在 Spring4.0就有了)
Objenesis objenesis = new SpringObjenesis();
 A a = objenesis.newInstance(A.class);

扩展阅读

Objenesis主要应用场景:

  • 序列化,远程调用和持久化 -对象需要实例化并存储为到一个特殊的状态,而没有调用代码
  • 代理,AOP库和Mock对象 -类可以被子类继承而子类不用担心父类的构造器。
  • 容器框架 -对象可以以非标准的方式被动态实例化(比如Spring就是容器框架)

# instanceof、isInstance、isAssignableFrom区别

参考答案

  • instanceof运算符 只被用于对象引用变量,检查左边的被测试对象 是不是 右边类或接口的 实例化。如果被测对象是null值,则测试结果总是false。

    • 伪代码:自身实例或子类实例 instanceof 自身类 返回true
    • 例:String s=new String("javaisland");
    • 例:System.out.println(s instanceof String); //true
  • Class类的isInstance(Object obj)方法,obj是被测试的对象,如果obj是调用这个方法的class或接口 的实例,则返回true。这个方法是instanceof运算符的动态等价。

    • 伪代码:自身类.class.isInstance(自身实例或子类实例) 返回true
    • 例:String s=new String("javaisland");
    • 例:System.out.println(String.class.isInstance(s)); //true
  • Class类的isAssignableFrom(Class cls)方法,如果调用这个方法的class或接口 与 参数cls表示的类或接口相同,或者是参数cls表示的类或接口的父类,则返回true。

    • 伪代码:自身类.class.isAssignableFrom(自身类或子类.class) 返回 true
    • 例:System.out.println(ArrayList.class.isAssignableFrom(Object.class)); //false
    • 例:System.out.println(Object.class.isAssignableFrom(ArrayList.class)); //true

# new String() 和 toString() 的区别

参考答案

  • toString() 是调用了Object 对象类的 toString() 方法,默认返回当前对象(c)的内存地址即hashCode。也就是[class name]@[hashCode]格式,如:[B@312b1dae
  • new String(para)是根据para是一个字节数组,使用Java虚拟机默认的编码格式,将这个字节数组decode为对应的字符,返回的是真实的值。

该问题发生在使用Socket读取客户端的字节流,把bytes.toString()却输出了hashCode值,而用new String(bytes)则正确的打出了值。

# 如何理解Java关键字this

参考答案

  • 首先,this关键字必须放在非静态方法里面。
  • 可以使用this关键字引用成员变量。
  • 使用this关键字在自身构造方法内部引用其它构造方法。
  • 使用this关键字代表自身类的对象。
  • 使用this关键字引用成员方法。

this关键字是一个对象的默认引用。作为对象的默认引用,有两种情形:

  1. 构造器中,引用该构造器执行初始化的对象。
  2. 方法中,引用调用该方法的对象。

# 构造方法的作用

参考答案

  • 首先每个类都有一个无参数的默认构造函数。这也是为什么有些类即便没有写构造方法也可以通过new来实例化。
  • 为了初始化成员属性,而不是初始化对象,初始化对象是通过new关键字实现的。
  • 通过new调用构造方法初始化对象,编译时根据参数签名来检查构造函数。
  • 创建子类对象会调用父类构造方法但不会创建父类对象,只是调用父类构造方法初始化父类成员属性;

扩展阅读

构造器中一定不要创建自身的实例,否则会造成调用栈溢出错误。

class a
{
  a _a = new a();
   public a()
  {
    _a = new a();
    a _b = new a();
  }
}

以上三种情况都会造成栈溢出,会造成一个无穷递归的调用栈。

注意事项

继承中的构造方法,有下面这些规则需要遵守

  • 1.子类的构造过程中必须调用其父类的构造方法
  • 2.子类可以在自己的构造方法中使用super(参数列表)调用父类的构造方法
  • (1).可以使用this(参数列表)调用自己这个类的其他的构造方法 调用this的时候也调用了父类的构造方法
  • (2).如果调用了super,必须写在子类构造方法的第一行
  • (3).this也必须放在第一行,所以this,super在一个构造方法里无法同时出现 实际上严格来讲,还是能实现的,用内部类。在内部类里面,可以使用一个this或者super
  • 3.如果子类的构造方法中没有显示地调用父类构造方法,系统默认调用父类那个无参数的构造方法
  • 4.如果子类构造方法中既没有显示调用父类构造方法,而父类中又没有无参的构造方法,编译会报错。 构造器中一定不要创建自身的实例,否则会造成调用栈溢出错误。