Java基础面试题

Java基础面试题

最近在准备面试,所以将一些常见的面试题解析整理出来,方便复习。

 

01_字符串常量Java内部加载-上

由于运行时常量池是方法区的一部分,所以这两个区域的溢出测试可以放到一起进行。HotSpot从JDK 7开始逐步“去永久代”的计划,并在JDK 8中完全使用元空间来代替永久代的背景故事,在此我们就以测试代码来观察一下,使用"永久代"还是“元空间"来实现方法区,对程序有什么实际的影响。

String:intern()是一个本地方法,它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

public class StringInternDemo {

    public static void main(String[] args) {

        String str1 = new StringBuilder("58").append("tongcheng").toString();

        System.out.println(str1); // 58tongcheng

        System.out.println(str1.intern()); // 58tongcheng

        System.out.println(str1 == str1.intern()); // true

        System.out.println();

        String str2 = new StringBuilder("ja").append("va").toString();
        System.out.println(str2);  // java
        System.out.println(str2.intern());  //java
        System.out.println(str2 == str2.intern()); //false

    }

}

02_字符串常量Java内部加载-下

按照代码结果,Java字符串答案为false必然是两个不同的java,那另外一个java字符串如何加载进来的?

有一个初始化的Java字符串(JDK出娘胎自带的),在加载sun.misc.Version这个类的时候进入常量池。

递推步骤

  • System代码解析 System -> initializeSystemClass() -> Version
  • 类加载器和rt.jar - 根加载器提前部署加载rt.jar

  • OpenJDK8源码

    • http://openjdk.java.net/
    • openjdk8\jdk\src\share\classes\sun\misc

JDK 7(以及部分其他虚拟机,字符串常量池已经移到Java堆中,只需要在常量池里记录一下首次出现的实例引用即可,因此intern()返回的引用和由StringBuilder创建的那个字符串实例就是同一个。而对str2比较返回false,这是因为“java”这个字符串在执行StringBuilder.toString()之前就已经出现过了,字符串常量池中已经有它的引用,不符合intern()方法要求“首次遇到"”的原则,“计算机软件"这个字符串则是首次出现的,因此结果返回true。

sun.misc.Version类会在JDK类库的初始化过程中被加载并初始化,而在初始化时它需要对静态常量字段根据指定的常量值(ConstantValue〉做默认初始化,此时被sun.misc.Version.launcher静态常量字段所引用的"java"字符串字面量就被intern到HotSpot VM的字符串常量池——StringTable里了。
 

03_String经典面试题

class StringTest {

    String str = new String("good");  //数组和对象传递地址,其他数据类型传递的是数据
    char[] ch = { 't', 'e', 's', 't' };

    public void change(String str, char ch[]) {  //String str str是新的一个变量,在常量池中是test ok
        str = "test ok";   //this.str = "test ok"
        ch[0] = 'b';
    }
    public static void main(String[] args) {
        StringTest ex = new StringTest();
        ex.change(ex.str, ex.ch);
        System.out.println(ex.str); //good
        System.out.println(ex.ch);  //best
    }
}
public class TestTransferValue {

   public void changeValue1(int age){
       age = 30;
   }

    public void changeValue2(Person person){
       person.setPersonName("xxx");
    }

    public void changeValue3(String str){
       str = "xxx";
    }

    public static void main(String[] args) {

        TestTransferValue test = new TestTransferValue();

        /**
         * 在changeValue1方法中对age复制了一份,不影响main中的age值【基本类型传复印件age】
         */
        int age = 20;
        test.changeValue1(age);
        System.out.println("age -----" + age);    // age -----20

        /**
         * main和changeValue2方法都指向了 new Person("abc")的内存地址,所以会改变main中的person值
         * 指针指向了同一个引用地址
         */
        Person person = new Person("abc");
        test.changeValue2(person);
        System.out.println("personName-----" + person.getPersonName());  // personName-----xxx

        /**
         * String直接赋值,str = "abc",则main指向abc,changeValue3方法中String刚开始指向abc,
         * 然后 str = "xxx",没有这个值,需要新建一个xxx,这时changeValue3的指向了xxx
         */
        String str = "abc";
        test.changeValue3(str);
        System.out.println("String--------" + str); //  String--------abc

        person.personName = "jjjjj";
        System.out.println(person.personName);  //jjjjj
        
    }

}
    @Test
    public void test3(){
        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        String s4 = "javaEE" + "hadoop"; //在方法区的常量池中
        String s5 = s1 + "hadoop";       //在堆空间中,类似于new
        String s6 = "javaEE" + s2;
        String s7 = s1 + s2;

        System.out.println(s3 == s4);//true
        System.out.println(s3 == s5);//false
         
        String s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop” 在方法区的常量池中
        System.out.println(s3 == s8);//true

    }

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值