java基础面经

  1. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
     答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。

  2. Java中会存在内存泄露吗?
    答:Java语言也存在内存泄露问题。Java语言提供了垃圾回收机制,它可以自动回收那些不再被使用的对象,以释放内存空间,但是也会存在编程导致的内存泄露问题,通常是不再使用的对象,但是程序又持有对该对象的引用,从而导致该对象无法被回收的情况称为内存泄露。

  3. 局部变量可以定义私有修饰类型吗?
    下面代码要实现doSomething()方法中局部变量的定义,看看这段代码中的定义是否正确?

    public class Something {
        void doSomething() {
            private String s = "";
            int l = s.length();
        }
    }
    

    答:这样编码是错误的,定义变量s的语句无法通过编译。局部变量前不能放置任何访问修饰符,包括private、public和protected,但是final可以用来修饰局部变量,但这样修饰后,它会变为常量。

  4. 用最有效率的方法算出2乘以16等于几?
    解析:位运算的效率是最高的,所以要想找出最有效率的运算方法,应该从位运算入手,Java语言的位运算中提供了左移、右移和无符号右移运算符,它们分别是<<、>>、>>>。左移运算会把操作数变大,它相当于把左侧操作数乘以2的N次幂,这个N是由右操作数决定的。而右移运算恰恰相反,它实现的是除法。
    答案:2 << 4

  5. 在Java1.6中byte、long和String类型是否可以作为switch语句的判断表达式。
    解析:switch语句中的判断表达式类型是int,因此传递给switch和case语句的参数类型必须低于int类型。支持类型包括int、short、char和byte。但是long类型不可以,而String类型在Java1.6和之前的版本中都不支持。
    答案:byte类型可以应用与switch语句中,但是long不可以,而String类型目前也不可以。

  6. 可以通过哪几种方式创建字符串
    解析:在Java中使用String类来声明和创建字符串。要创建字符串可以通过多种方式实现。
    (1)通过String类的构造方法可以创建字符串对象,例如:
    String sVar = new String(“good”); // 创建初始内容为good的字符串
    (2)也可以通过为字符串变量赋值的方式来实例化字符串对象,例如:
    String sVar = “good”; // 声明字符串变量时为变量赋值来创建字符串
    (3) 在Java中还可以通过方法调用来实例化字符串对象,例如:
    int x=100; // 创建整型变量x,其初值为100
    String sVar = String.valueOf(x); // 通过String类的valueOf方法实例化字符串对象
    答案:在Java中可以使用3种方式来创建字符串对象,第一种是通过String类的构造方法来创建字符串对象,第二种是通过为字符串变量赋值字符串常量创建字符串对象,第三种方式是通过方法调用来实例化字符串对象。

  7. 说明Java中String str = null与String str = ""的区别。
    解析:空字符串和赋值为null的字符串在使用中极易混淆。这是由求职者对空字符串的理解不够准确造成的。当一个字符串被赋值为null时,它并没有被分配任何的内存空间,而只是声明了一个字符串变量。空字符串拥有内存空间,它只是长度为0而已。求职者只有真正理解了空字符串的定义才能避免在使用空字符串过程中出现的不必要的问题。
    答案:String str = null表示声明了一个String对象的引用str,但是没有为其分配内存空间,而String str = ""则表示创建了一个长度为0的空字符串,并在内存中为其分配了内存空间。

  8. 如何实现字符串的反向输出?
    答案:在Java中没有为String类提供进行反向输出的方法,为此可以自己编写实现字符串反向输出的代码,下面是笔者使用的两种方法:
    第一种方法就是使用String类的split()方法对字符串进行分隔,分隔后返回与该字符串对应的字符串数组,然后逆序输出字符串数组中的每个元素,从而可以实现字符串的反向输出。
    第二种方法就是使用String类的charAt()方法通过字符串的索引值逆序输出字符串中的每一个元素,这样也可以实现字符串的反向输出。

  9. 使用运算符“==” 和方法equals、hashcode的区别
    (1)基本变量没有hashcode和equals方法,基本变量的比较方式就只有= =;
    (2)equals比较对象时,先比较内存地址,地址相同,返回true,地址不同,再比较值。“= =”之间比较地址是否相同
    (3)object类的equals方法和= =一样是比较地址,String类中的equals方法是重写了。所以自定义类需要重新equals方法
    (4)没有重写hashcode和equals的情况下,两者没有关联。例如new Object() 其hashcode永远是不同的。为了用在HashSet, HashTable, HashMap等数据结构中,需要重写自定义的类的hashcode和equals方法,保证equals相等时,hashcode相等;但是hashcode相同时,equals不一定相同(因为存在哈希冲突)
    参考博客:http://blog.sina.com.cn/s/blog_6ac4c6cb010149m6.html
    https://www.cnblogs.com/justdojava/p/11271438.html

  10. 在Java中如何判断字符串为空
    解析:在Java语言中,字符串为空有两层含义,一种是空值null,另一种是0长度的空字符串。
    1.使用String类声明字符串变量时,将其初始化为null,此时可以使用关系
    运算符 = = 进行判断。
    使用关系运算符判断字符串为空值null,代码如下:
    String sVar = null;
    if (sVar = = null) {
    // 字符串为空时需要执行的代码
    }

2.使用String类声明字符串变量时,为其指定了0长度的空字符串,此时可以使用equals()方法或使用length()方法进行判断。 使用equals()方法判断字符串是否为空,代码如下:
String sVar = “”;
if (sVar.equals(“”)) {
// 字符串为空时需要执行的代码
}
使用length()方法结合关系运算符“= =”判断字符串为空,代码如下:
String sVar = “”;
if (sVar.length() = = 0) {
// 字符串为0长度时需要执行的代码
}
答案:在Java中可以使用关系运算符“= =”判断字符串是否为空值null,可以使用equals()方法,并为其传递一个空字符串作为实参,从而可以实现判断字符串是否为空的功能,或使用length()方法结合关系运算符“==”来判断字符是否为0长度,实现判断字符串为空的功能。

  1. Java语言规范中,对equals()方法有何要求? (1)自反性:对于任何非空引用值x,x.equals(x)都应返回true;
    (2)对称性:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true;
    (3)传递性:对于任何非空引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)应返回true。;
    (4)一致性:对于任何非空引用值x和y,多次调用x.equals(y)始终返回true或始终返回false,前提是对象上equals比较中所用的信息没有被修改;
    (5)对于任何非空引用值x,x.equals(null)都应返回false。

  2. 以下声明合法的是(B)

A、default Strings;B、public final static nativeintw( )

C、abstract doubled;D、abstract final double hyperbolicCosine( )

A不是,default不是合法修饰符(修饰符在不写的时候有默认值,但是default不是修饰符)
C不是,不存在abstract的变量,只有abstract方法
D不是,abstract和final不能同时出现,自相矛盾

  1. ArrayList list = new ArrayList(20);中的list扩充几次

ArrayList list=new ArrayList(); 这种是默认创建大小为10的数组,每次扩容大小为1.5倍
ArrayList list=new ArrayList(20); 这种是指定数组大小的创建,创建时直接分配其大小,没有扩充。
所以,扩充为0次

  1. try ,catch,finally执行顺序

  2. Java中面向对象编程的核心

  3. Object中有哪些方法

getClass()    //返回此 Object 的运行类。
hashCode()    //用于获取对象的哈希值。
equals(Object obj)     //用于确认两个对象是否“相同”。
clone()    //创建并返回此对象的一个副本。
toString()   //返回该对象的字符串表示。
notify()    //唤醒在此对象监视器上等待的单个线程。
notifyAll()     //唤醒在此对象监视器上等待的所有线程。
wait(long timeout)    //在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或        者超过指定的时间量前,导致当前线程等待。
wait(long timeout, int nanos)    //在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
wait()    //用于让当前线程失去操作权限,当前线程进入等待序列
finalize()    //当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
  1. 深拷贝和浅拷贝的区别
    浅拷贝仅仅复制所拷贝的对象,而不复制它所引用的对象
    深拷贝把要复制的对象所引用的对象都复制了一遍
    1. 浅拷贝只实现Cloneable接口重写了外层类的clone方法, 如果外层类包含基础数据类型, 则直接拷贝值, 是新的变量, 但是如果外层类包含引用数据类型, 只拷贝了引用对象的地址. 但是原对象和拷贝对象是两个对象. 对象拷贝的话原对象和拷贝对象是同一个对象
    2. 深拷贝需要重写多层对象的所有clone()方法
package code.java_based;

import org.junit.Test;

public class CloneTest {
    @Test
    public void func() throws CloneNotSupportedException {
        // 浅拷贝
        int[] ints = {1,2,3};
        String name = "zhangxiangyang";
        int age = 23;
        Person person = new Person("zhangxiangyang",age,ints);
        System.out.print("一:克隆前:  age = "+ age + "... name = "+ name + " 数组:");
        for (int i : ints){
            System.out.print(i + " ");
        }

        System.out.println();


        //拷贝
        Person clonePerson = (Person) person.clone();

        int clonePersonAge = clonePerson.getAge();
        String clonePersonName = clonePerson.getName();
        int[] ints1 = clonePerson.getInts();

        System.out.print("二:克隆后: age = "+ clonePersonAge + "... name = "+ clonePersonName + " 数组: ");
        for (int i : ints1){
            System.out.print(i + " ");
        }
        System.out.println();
        //修改:
        ints1[0] = 50;
        //修饰
        clonePerson.setName("666666666");

        age = person.getAge();
        name = person.getName();
        System.out.println();
        System.out.print("三:修改后原对象: age = "+ age + "... name = "+ name + "数组 ");
        for (int i : ints){
            System.out.print(i + " ");
        }
        System.out.println();
        System.out.println("四:person == clonePerson ? "+ (person == clonePerson ));
    }

    @Test
    public void func2() throws CloneNotSupportedException {
        // 深拷贝
        int[] ints = {1,2,3};
        String name = "zhangxiangyang";
        int age = 23;
        Person1 person = new Person1("zhangxiangyang",age,ints);
        System.out.print("一:克隆前:  age = "+ age + "... name = "+ name + " 数组:");
        for (int i : ints){
            System.out.print(i + " ");
        }

        System.out.println();


        //拷贝
        Person1 clonePerson = (Person1) person.clone();

        int clonePersonAge = clonePerson.getAge();
        String clonePersonName = clonePerson.getName();
        int[] ints1 = clonePerson.getInts();

        System.out.print("二:克隆后: age = "+ clonePersonAge + "... name = "+ clonePersonName + " 数组: ");
        for (int i : ints1){
            System.out.print(i + " ");
        }
        System.out.println();
        //修改:
        ints1[0] = 50;
        //修饰
        clonePerson.setName("666666666");

        age = person.getAge();
        name = person.getName();
        System.out.println();
        System.out.print("三:修改后原对象: age = "+ age + "... name = "+ name + "数组 ");
        for (int i : ints){
            System.out.print(i + " ");
        }
        System.out.println();
        System.out.println("四:person == clonePerson ? "+ (person == clonePerson ));
    }
}

/**
 * 浅拷贝
 */
class Person implements Cloneable{
    private String name;
    private int age;
    private int[] ints;

    public int[] getInts() {
        return ints;
    }

    public Person(String name, int age, int[] ints) {
        this.name = name;
        this.age = age;
        this.ints = ints;
    }

    public void setInts(int[] ints) {
        this.ints = ints;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     *  默认实现
     * */
    @Override
    public Object clone() throws CloneNotSupportedException {
        return  super.clone();
    }
}

/**
 * 深度拷贝
 */
class Person1 implements Cloneable{
    private String name;
    private int age;
    private int[] ints;

    public int[] getInts() {
        return ints;
    }

    public Person1(String name, int age, int[] ints) {
        this.name = name;
        this.age = age;
        this.ints = ints;
    }

    public void setInts(int[] ints) {
        this.ints = ints;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person1(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     *  深拷贝
     * */
    @Override
    public Object clone() throws CloneNotSupportedException {
        Person1 person = new Person1(name,age);
        int[] ints = new int[this.ints.length];
        System.arraycopy(this.ints,0,ints,0,ints.length);
        person.setInts(ints);
        return  person;
    }
}

参考博客https://blog.csdn.net/riemann_/article/details/87217229
https://www.cnblogs.com/lgxblog/p/11568153.html

  1. BIO、NIO、AIO的区别
    IO,常写作I/O,是Input/Output的简称,即输入/输出。通常指数据在内部存储器(内存)和外部存储器(硬盘、优盘等)或其他周边设备之间的输入和输出:BIO 全称Block-IO 是一种同步且阻塞的通信模式;Java NIO,全程 Non-Block IO ,是Java SE 1.4版以后,针对网络传输效能优化的新功能。是一种非阻塞同步的通信模式;Java AIO,全程 Asynchronous IO,是异步非阻塞的IO。是一种非阻塞异步的通信模式。在NIO的基础上引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现
    三者的主要区别
    BIO (Blocking I/O):同步阻塞I/O模式。
    NIO (New I/O):同步非阻塞模式。
    AIO (Asynchronous I/O):异步非阻塞I/O模型
    比方
    同步阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,并坐在水壶面前一直等着水烧开。
    同步非阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,但是我们不一直坐在水壶前面等,而是回到客厅看电视,然后每隔几分钟到厨房看一下水有没有烧开。
    异步非阻塞I/O模型:这种模式下,我们的工作模式是先来到厨房,开始烧水,我们不一一直坐在水壶前面等,也不隔一段时间去看一下,而是在客厅看电视,水壶上面有个开关,水烧开之后他会通知我
    适用场景
    BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
    NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
    AIO方式适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持
    参考博客https://blog.csdn.net/csdnlijingran/article/details/88935059
    Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

  2. Java反射

    • 什么是Java的反射?
      在运行状态中,对于任意一个类,都能够知道这个类的属性和方法;
    • 反射的作用?
      如果给定一个类名,就可以通过反射机制来获取类的所有信息,也可以动态的创建对象和编译;
    • 反射的原理?
      Java语言在编译之后会生成一个class文件,反射就是通过字节码文件找到其类中的方法和属性等;
    • 反射的实现主要借助以下四个类:
      java.lang.Class; //类的对象
      java.lang.reflect.Constructor;//构造方法
      java.lang.reflect.Field; //类的成员变量
      java.lang.reflect.Method;//类的方法
      java.lang.reflect.Modifier;//访问权限
    • 反射的三种方式
      Class cla = new Student().getClass();
      Class cla = new Student().class;
      Class cla = Class.forName("xx.xx.Student");
      
      Method method = cla.getDeclaredMethod("funcName", Integer.class);
      method.invoke(new Student(), 1);
      
    • 应用场景
      在过去通过访问servlet访问接口方式中,因为一个servlet中只有一个doGet或doPost。往往需要很多servlet。在一个servlet中添加多个方法,请求的时候,携带方法名,通过在servlet的service通过反射机制,创建当前servlet对象,然后调用该方法。
  3. String为什么设计成定长的(为什么设计成不可变的)

    • 便于实现字符串池:在Java中,由于会大量的使用String常量,如果每一次声明一个String都创建一个String对象,那将会造成极大的空间资源的浪费。Java提出了String pool的概念,在堆中开辟一块存储空间String pool,当初始化一个String变量时,如果该字符串已经存在了,就不会去创建一个新的字符串变量,而是会返回已经存在了的字符串的引用
    • 加快字符串处理速度:由于String是不可变的,保证了hashcode的唯一性,于是在创建对象时其hashcode就可以放心的缓存了,不需要重新计算。这也就是Map喜欢将String作为Key的原因,处理速度要快过其它的键对象。所以HashMap中的键往往都使用String
  4. String的直接赋值和构造参数实例化有什么区别
    直接赋值

	public class StringDemo{
	public static void main(String[] args) {
		String str1 = "Hello qty";
		String str2 = "Hello qty";
		String str3 = "Hello qty";
		String str4 = "Hello ytq";
		System.out.println(str1==str2); // true
		System.out.println(str1==str3); // true
		System.out.println(str2==str3);// true
		System.out.println(str1==str4); // false
	}
}

在这里插入图片描述构造函数赋值

public class StringDemo{
	public static void main(String[] args) {
	String str1 = new String("Hello qty");
	String str2 = "Hello qty";
	System.out.println(str1==str2); // false
	}
}

在这里插入图片描述
在这里插入图片描述
构造方法实例化这种方式比较于直接赋值的缺陷所在,多开辟了一块堆内存,存在垃圾问题
参考博客https://www.cnblogs.com/wkfvawl/p/11693260.html https://blog.csdn.net/qty4505861/article/details/82826492
美团面试题:String s = new String(“111”)会创建几个对象?

  1. 项目中遇到过内存溢出的问题

    1. 代码中出现了死循环
    2. 对文件的io操作,没有在finally中关闭文件流
  2. hashtable,concurrenthashmap为什么键和值不能为null,而hashmap可以?
    hashtable,concurrenthashmap中 value不为null的原因
    因为hashtable,concurrenthashmap它们是用于多线程的,并发的 ,如果map.get(key)得到了null,不能判断到底是映射的value是null,还是因为没有找到对应的key而为空,而用于单线程状态的hashmap却可以用containKey(key) 去判断到底是否包含了这个null。
    hashtable为什么就不能containKey(key)
    一个线程先get(key)再containKey(key),这两个方法的中间时刻,其他线程怎么操作这个key都会可能发生,例如删掉这个key
    key不为null的原因:在hashmap中
    在这里插入图片描述
    HashMap在put的时候会调用hash()方法来计算key的hashcode值,可以从hash算法中看出当key==null时返回的值为0。因此key为null时,hash算法返回值为0,不会调用key的hashcode方法。
    Hashtable存入的value为null时,抛出NullPointerException异常。如果value不为null,而key为空,在执行到int hash = key.hashCode()时同样会抛出NullPointerException异常
    从设计师角度分析
    Hashtable是Java中的遗留类,现在不怎么用了,这里HashMap vs Hashtable有个解释。也许Hashtable类的设计者当时认为null作为key 和value 是没有什么用的。
    HashMap是之后的版本引进的类,它的接口Map表达的意义更为广泛,也许HashMap的设计者认为null作为key和value是有实际意义的,所以才允许为null.
    当然实际项目中,真的是有value为null的情况的。key为null的情况比较少见,但不代表没有。HashMap允许null为key和value应当是类的设计者思考让这个类更有用的设计吧。
    参考博客:https://blog.csdn.net/qq_25560423/article/details/77713423 https://blog.csdn.net/HD243608836/article/details/88052088

  3. static关键字

    • 作用
      (1)为某特定数据类型或对象分配单一的存储空间, 而与对象的创建数量无关(2) 实现某个方法或属性与类关联, 而不是与对象关联
    • static修饰的方法能否访问成员变量
      不能, statc修饰的方法可以在类未实例化的时候使用, 而类未实例化时成员变量并未初始化, 简单说就是static方法只能访问static变量
  4. Java泛型

    • https://www.cnblogs.com/minikobe/p/11547220.html
    • https://blog.csdn.net/vincentmiaozhuang/article/details/1790936
    • 不考虑对象的具体类型, 就能对对象进行一定的操作, 对任何对象都能进行相同的操作
    • 局限性: 一般不可以使用对象自带的接口函数(可以使用接口限定), 因此只适合作为容器类
    • 范型是编译器层面的操作, 需要在进入虚拟机之前擦除成普通类
  5. 重载的优点

    1. 方法定义者使用相同的方法名来表示功能相同的多个方法
    2. 使用者可以使用相同名字实现不同功能
    3. 多态的体现
  6. Java访问权限

  7. java中override、overload和overwrite区别

    • override: 覆写和(overwrite: 重写): 实现接口的方法,重写父类的方法
    • overload: 重载: 和父类相同的类名和返回值, 有不同的入参
  8. GBK和utf-8的区别

    • GBK无论中英文均使用双字节表示, 包含全部中文字符
    • utf-8对于英文使用1字节表示, 中文使用3字节表示, 包含全世界所有国家需要用到的字符
  9. int和Integer的区别

    • int是基础类型, Integer是int的包装类, 有方法和属性
    • int默认值是0, Integer默认值是null
    • int存储在栈中, Integer引用存储在栈中, 实际对象存储在堆中
  10. 抽象类和接口

    • 抽象类是对根源的抽象, 接口是对动作的抽象
    • 抽象类可以有构造方法和普通成员变量, 接口内没有
    • 抽象类可以包含静态方法, 接口不可以, 一个类可以实现多个接口, 但只能继承一个抽象类
  11. 多继承的问题
    不同父类中同名成员变量和函数的取舍. 如B和C都继承了A, 重写了其中的方法, D同时继承了B和C的话, 无法判断使用哪个同名方法

  12. HashMap的put和get过程
    Entry是HashMap数组中的元素, 每个Entry其实是一个键值对的映射, 持有指向下一个元素的引用, 构成了链表
    https://blog.csdn.net/yao_shen_yun/article/details/94451122

    • put
      1. 判断键值对数组table[i]是否为空或者为null, 否则进行扩容
      2. 根据键key计算hash值得到插入的数组索引i, 如果table[i] == null, 直接添加新节点, 转6, table[i]非空则转3
      3. 判断table[i]的首个元素是否和key一样(hashCode和equals), 一样则覆盖, 否则4
      4. 判断table[i]是否时红黑树, 如重载果是红黑树则直接插入, 如果不是转5
      5. 判断链表长度是否大于8, 大于8时把链表转换成红黑树, 进行插入操作
      6. 插入成功后, 判断实际存在的键值对数量是否超过阈值, 超过则扩容(扩容条件: put时当前元素个数大于阈值 && 存放新值的时候发生hash碰撞)
    • get
      1. 得到key的hash值
      2. 调用内部方法得到桶号
      3. 比较桶的内部元素是否和key相等, 不相等则没找到, 相等则取出相等记录的value
        1. 链表遍历
        2. 红黑树find()
  13. Short s=1; s+=1有错吗?没错的话结果是什么?
    错, short运算时会转换成int, Short无法转换成Integer (+=会对右边的表达式结果强转匹配左边的数据类型)

  14. Float f=3.4有错吗,为什么?
    错, float单精度, 不指明f都是双精度double

  15. String, StringBuilder和StringBuffer

    • String定长, 修改长度指向新的内存地址, 频繁修改内存消耗大
    • StringBuilder: 线程不安全, 速度快
    • StringBuffer: 线程安全
  16. String对象的intern()方法: 从常量池中查找是否存在该常量值的字符串, 若不存在则在常量池中创建, 否则直接返回常量池中已存在的字符串的引用
    JDK6
    Jdk6中常量池位于PermGen(永久代)中。执行intern()方法时,若常量池中不存在等值的字符串,JVM就会在常量池中创建一个等值的字符串,然后返回该字符串的引用
    JDK7
    Jdk7将常量池从PermGen区移到了Java堆区,执行intern操作时,如果常量池已经存在该字符串,则直接返回字符串引用,否则复制该字符串对象的引用到常量池中并返回

    做题
    public static void main(String[] args) {
    String s = new String(“1”);
    s.intern();
    String s2 = “1”;
    System.out.println(s == s2);

    String s3 = new String("1") + new String("1");
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);
    

    }
    jdk6 下false false
    jdk7 下false true
    public static void main(String[] args) {
    String s = new String(“1”);
    String s2 = “1”;
    s.intern();
    System.out.println(s == s2);

    String s3 = new String("1") + new String("1");
    String s4 = "11";
    s3.intern();
    System.out.println(s3 == s4);
    

    }
    jdk6 下false false
    jdk7 下false false
    String的Intern方法详解

  17. List如何一边遍历,一边删除
    【Java面试题】List如何一边遍历,一边删除?

  18. Java的外部类为什么不能使用private、protected进行修饰
    对于顶级类(外部类)来说,只有两种修饰符:public和默认(default)。因为外部类的上一单元是包,所以外部类只有两个作用域:同包,任何位置。因此,只需要两种控制权限:包控制权限和公开访问权限,也就对应两种控制修饰符:public和默认(default)。
    参考博客:Java的外部类为什么不能使用private、protected进行修饰

  19. java中4种修饰符访问权限的区别及详解全过程

  20. final关键字的实现
    1-修饰类
    表明这个类不能被继承,final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
    2-修饰方法
    使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。
    3-修饰变量
    对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象
    浅析Java中的final关键字

  21. 虚拟机如何实现多态
    动态绑定, 执行期间判断引用对象的实际类型
    invokevirtual:调用所有的虚方法,即对应涉及到多态方法
    (1)找到操作数栈顶的第一个元素所指向的对象的实际类型,记为C;
    (2)如果在类型C中找到与常量中的描述符和简单名称一样的方法,,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束
    细说JVM(虚拟机实现多态)

  • Java中假定finalize的工作原理为
    一旦垃圾回收器准备回收内存而释放对象所占内存的时候,会先调用该对象的finalize方法,然后在下一次再需要垃圾回收的时候才真正的回收对象!

为解决问题:

  1. java项目包括springboot第一次启动相对于c或c++慢一点,后面就可以调整到差不多,这是为什么
  2. java采用混合编译,具体哪些采用即时编译哪些采用
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值