ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java基础面试题----持续补充

2022-02-24 11:32:37  阅读:207  来源: 互联网

标签:面试题 abc java String int ArrayList System ---- new


主文章(我总结的面试题的索引目录—进不去就说明我还没写完)
https://blog.csdn.net/grd_java/article/details/122357831
字节码指令可以到这篇文章查:https://www.cnblogs.com/longjee/p/8675771.html

文章目录

1. 语法细节

1. switch是否能作用在byte上,long呢,String呢?

  1. Java 5之前,switch(expr),expr只能是byte、char、int、short
  2. Java 5之后,java引入enum枚举类型,expr可以支持enum类型
  3. Java 7开始,expr可以作用于字符串String类型,long类型在目前所有版本中都不支持

2. java注释有几种,注释有什么用

  1. java注释有3种,//单行注释,/* 多行注释 * /,/**文档注释 */,其中多行和文档注释不能嵌套
  2. 注释作用:复杂程序中,适当加入注释,可以增加程序可读性,利用程序修改、调试和交流,注释内容在程序编译时会被忽略,不会对程序执行结果产生任何影响

3. & 和 && 的区别,| 和 || 的区别

  1. &运算符有两种用法:按位与,逻辑与
  2. &&运算符是短路与运算,逻辑与和短路与,差别巨大。二者都要求运算符左右两端布尔值都是true,运算结果才为true。
  3. &&称为短路与的原因是,如果左边表达式为false,右边表达式直接短路,不进行运算
  4. 而&无论前面已经运算的是不是false,都会和后面的进行运算,不会短路
  5. 逻辑或运算符(|)和短路或运算符(||)的差别也是如此

4. final 的作用

  1. 修饰符,可以修饰类、属性、方法,表示最终的,被修饰的对象不可改变
  2. 被final修饰的类不可被继承
  3. 被final修饰的方法不可以被重写
  4. 被final修饰的变量不可以被改变,针对的是变量的引用,引用不可变,引用指向的内容可变

4. final int a = 1; a = 10;正确吗?final Test test = new Test(“zhangsan”);test.name = “lisi”;正确吗?

  1. final int a = 1; a = 10;不正确,因为1是一个常量,在堆栈中存着,a变量指向了1.此时执行a=10;会将a的引用指向10,而final修饰的变量不可以变换引用,所以不正确
  2. final Test test = new Test(“zhangsan”);test.name = “lisi”;是正确的,test的引用始终没变过,final修饰的变量,只有引用不可变内容可变test.name = "lisi";改的是内容

5. break,continue,return的区别和作用

  1. break 跳出当前层循环,不在执行当前循环体(不影响外层循环),switch中直接跳出switch
  2. continue 跳出本次循环,继续执行下次循环(结束本次循环,直接判断下一个循环条件)
  3. return 程序返回,不在执行下面代码(结束当前方法,直接返回)

6. java多重嵌套循环中,如何跳出指定层循环?

  1. java提供循环标签,break和continue可以指定跳出相应标签的循环
    在这里插入图片描述

7. == 和 equals 区别是什么

  1. ==:运算对象是基本数据类型时,比较的是值(两个值相不相同)。运算的是引用类型时,比较两个对象内存地址是否相同(看两个对象是不是同一个对象)
  2. equals():判断两个对象是否相等
  1. 类没有覆盖equals()方法,则比较两个对象内存地址,和 == 一样
  2. 类覆盖了equals()方法,看具体覆盖的实现,比如我们判断两个对象内容是否相等,相等返回true

8. String str = "i"与String str=new String(“i”)一样吗?

  1. 不一样,因为内存分配方式不一样
  2. String str = "i"的方式,java虚拟机会将其分配到常量池中(常量池:存储常量)
  3. String str=new String(“i”)的方式,会将其分配到堆内存中(堆:存储new出来的),然后堆指向常量池,并不是直接指向常量池的"i"
  4. 还不理解,看下面代码
    public static void main(String[] args) {
        String a = "abc";//直接将"abc"放在常量池,然后栈中a直接指向常量池"abc"
        String b = "a"+"bc";//直接将结果算出来"abc",然后栈中b直接指向常量池"abc"
        String c = new String("abc");//new String是多余的,先在堆中开辟内存,c指向堆,堆指向常量池"abc"
        System.out.println(a.equals(b)+"     "+c.equals(a));//true true,表示a、b、c的值相同
        System.out.println(a.hashCode()+"    "+ b.hashCode()+"     "+c.hashCode());//3个hashCode值都相同,表示他们最终指向的都是同一个"abc"
        System.out.println(
                System.identityHashCode(a)+"    "+
                System.identityHashCode(b)+"    "+
                System.identityHashCode(c)
        );//356573597    356573597    1735600054,可见a和b的内存地址相同,c的内存地址不同,因为a和b直接指向常量池,而c指向堆

    }
  1. 拓展(下面是代码的字节码文件,也就是运行时,执行的汇编指令,先看代码再看字节码
    在这里插入图片描述
    public static void main(String[] args) {
        String a = "abc";//直接将"abc"放在常量池,然后栈中a直接指向常量池"abc"
        String b = "a"+"bc";//直接将结果算出来"abc",然后栈中b直接指向常量池"abc"
        String d = "abc"+"";//直接将结果算出来"abc",然后栈中d直接指向常量池"abc"
        /**
         * 变量参与运算,
         * 根据a拿到"abc",
         * 然后StringBuilder sb = new StringBuilder();
         * 然后sb.append("abc");然后sb.addpen("")
         * sb.toString(),将StringBuilder搞成String,源码是return new String(value, 0, count);
         * 既然new了,那么现在堆中开辟空间
         * call指向堆,然后堆指向"abc"
         */
        String call = a + "";
        System.out.println(a.hashCode()+"   "+call.hashCode());//96354   96354,说明call和a的值都是常量池的"abc"
        System.out.println(
                System.identityHashCode(a)+"    "+
                System.identityHashCode(b)+"    "+
                System.identityHashCode(d)+"    "+
                System.identityHashCode(call)
        );//356573597    356573597    356573597    1735600054,a、b、d 都直接指向常量池"abc" . call指向堆,然后堆指向"abc"

    }

9. String、StringBuffer、StringBuilder的区别于联系

  1. String类是不可变类,一个String对象被创建后,字符序列不可变(字符串是常量),直至对象被销毁(当我们变量换引用后,原来的字符串常量,没有引用指向它,就会被当做垃圾,被JVM底层垃圾回收算法回收)
  2. StringBuffer类代表一个字符序列可变的字符串,通过append、insert、reverse、setCharAt、setLength等方法操作其内容。当需要生成最终字符串时,通过toString方法将其转变为String(并不是StringBuffer变成String,而是根据值,返回一个String对象)
  3. JDK1.5新增了一个StringBuilder类,与StringBuffer类似,构造方法和方法基本相同。但是StringBuffer是线程安全的,StringBuilder是线程不安全的,性能略高。通常,创建一个可变字符串,优先StringBuilder
  4. StringBuffer:JDK1.0就有,效率相对较低,线程安全
  5. StringBuilder:JDK1.5加入,效率高,线程不安全
  6. 三个类,底层维护的都是char[],但是String的char[] 是使用final修饰的,所以String类和它的char[]的引用不可改变,但是char[]中数组值可变,但是因为String类的char[]是private我们没法改,所以我们常说String是常量,不可变,想要变,只能new一个新的String或者指向其它字符串常量
  7. StringBuffer的数组,有初始长度为16,当满了以后,是可以扩容的(建立一个容量更大的新数组,然后将满的数组值拷贝),所以叫可变长字符串

10. int 和 Integer 的区别

  1. java很纯洁,但为了编程方便,依然引入了基本数据类型int,char等等,为了将这些基本数据类型当成对象操作,java为每种基本数据类型都引入了对应包装类(wrapper class),int包装类为Integer,Java 5开始引入了自动装箱/拆箱机制,二者可以相互转换。
  2. Java为每个原始类型都提供了包装类型
    boolean—>Boolean、char—>Character、byte—>Byte、short—>Short、Integer—>Integer、long—>Long、float—>Float、double—>Double

11. Java异常关键字

  1. try - 用于监听。可能抛出异常的代码放在try语句块中,当他们发生异常时,异常就被抛出
  2. catch - 用于捕获异常。catch用来捕获try语句块中发生的异常。
  3. finally - finally语句块总是会被执行。主要用于回收try块里打开的资源(数据库连接,网络连接,IO连接等)。finally执行完成后,才会回来执行try或者catch块中的return或throw语句,如果finally中使用return或throw等终止方法的语句,则不会跳回执行,直接停止
  4. throw - 用于抛出异常
  5. throws - 用在方法签名上,声明该方法可能抛出异常。

12. Java为什么只能单继承,但可以多实现接口

  1. 多实现方法,不会冲突,因为接口中没有方法体,所以实现都是再实现类中编写,,比如实现的两个接口都有a方法,因为两个接口都没方法体,具体实现再实现类中,不会冲突
  2. 多继承方法内容,容易冲突,继承的两个类都有a方法,两个父类各有各的实现,就会冲突

13. int value = 0;if(value||(value==0)) return true;会返回true吗?

  1. 不能,&&、||、!这些符号,都只能作用于boolean值,value是int类型数据,无法运算,编译错误

14. 已知String继承Object类,下面两个泛型集合,可以自动向上转型么?

List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list1 = list2;
  1. 不能,会编译错误;A继承B类,但是C< A >和C< B >不存在继承关系,是并列关系;

15. 已知String继承Object类,下面两个泛型集合,可以自动向上转型么?

List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<? extends Object> list3 = null;
list3 = list1;
list3 = list2;
  1. 完全可以,<? extends Object>是泛型受限(规定上限),只要是Object或继承于Object都可以受限转型

16. 已知A继承B类,下面代码可以正常运行吗?

List<Object> o = new ArrayList<>();
List<A> a = new ArrayList<>();
List<B> b = new ArrayList<>();
List<? extends B> list3 = null;
list3 = a;
list3 = b;
list3 = o;
  1. list3 = o;会编译错误,因为Object不是B类的子类

17. 已知A继承B类,下面代码可以正常运行吗?

List<Object> o = new ArrayList<>();
List<A> a = new ArrayList<>();
List<B> b = new ArrayList<>();
List<? super B> list3 = null;
list3 = a;
list3 = b;
list3 = o;
  1. list3 = a;会编译错误,<? super B> 是泛型受限(规定下限),只要是B类或B类的父类都可以受限转型,但是A类是B的子类,所以不可以受限转型,编译错误。

18. 下面代码中,对与方法参数List<?> list的操作,最终输出结果是什么?

public class A{
	public void a(List<?> list){
		for(Object o:list){
			System.out.println(o)
		}
		list.add("abc");
		list.add(null);
		Object s = list.get(0);
		System.out.println(s)
	}
}
class B{
	public static void main(String[] args){
		A a = new A();
		a.a(new ArrayList<String>());
		a.a(new ArrayList<Integer>());
	}
}
  1. list.add(“abc”);这行代码会编译错误,其它代码没问题,因为使用泛型通配符<?>,无法确定list中规定什么数据类型,所以无法进行具体类型的赋值操作,list.add(null);是没有问题的

2. 类型转换题

1. short s1=1;s1 = s1+1;有错吗?short s1=1;s1+=1;有错吗?

  1. 1int类型,s1short类型,s1+1自动向上转型,变成int型结果,需要强转(short)(s1+1)才可以赋值给s1
  2. short s1=1;s1+=1;可以正常编译,s1+=1;相当于s1=(short(s1+1));其中有隐含的强制类型转换

3. 概念题

1. java 面向对象的特征主要有几个方面?

  1. 封装:把对象属性私有化,有选择的提供可以被外界访问的属性和方法,如果外界没有任何访问某个类的方法,那么这个类没有意义
  2. 继承:继承父类的功能,以父类为基础,子类可以增加新的功能,也可以使用父类的功能,方便代码复用,是多态的前提
  1. 子类拥有父类非private的属性和方法
  2. 子类可以拥有自己的属性和方法,子类就是对父类进行扩展
  3. 子类可以自己实现父类的方法(重写)
  1. 多态:一个功能的多种访问(实现)形式,例如我们一个接口,可以有多个实现类,例如List接口,我们可以用ArrayList或LinkedList的实现。虽然调的都是List的方法,但是实现不同。同时也有方法重载,同名方法,根据参数列表不同,可以有不同的实现
  1. 重载:同名方法a,根据参数列表不同,调用不同的a方法
  2. 重写:将父类a方法推翻,自己定义新的实现
  3. 多态虽然提高扩展性,但是提高的不彻底,真正提高还得是反射,传个字符串可以反射任意类

2. 重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

  1. 两个都是实现多态的方式,区别在于前者实现的是编译时的多态性,后者实现的是运行时的多态性
  2. 重载:发生在同一个类中方法名相同参数列表不同参数类型不同,个数不同,顺序不同),与方法返回值和访问修饰符无关,重载方法不能根据返回类型进行区分
  3. 重写:发生在父子类中方法名、参数列表必须相同,返回值小于等于父类(自动向上转型),抛出的异常小于等于父类,访问修饰符大于等于父类(里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象);
  4. 如果父类方法访问修饰符为private则子类不能重写,子类中就算有同名方法,也不是重写

3. java内存分配

  1. 常量池:存放常量,例如"abc".处于方法区中,方法区的一部分
  2. 堆:存放用new产生的数据
  3. 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中(new 出来的对象)
  4. 寄存器:我们在程序中无法控制

4. 根据代码,判断结果

1. 下面代码中,两个数是否交换成功?

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        System.out.println("输出交换前的两个数:"+a+"---"+b);
        changeNum(a,b);
        System.out.println("输出交换后两个数"+a+"---"+b);
    }
    public static void changeNum(int num1,int num2){
        int t;
        t = num1;
        num1 = num2;
        num2 = t;
    }
}
  1. a和b的值交换没有成功,num1和num2的倒是换成功了
  2. 我们调用方法changeNum(a,b),此时传递的是值,将10和20传了过去给num1和num2
  3. changeNum()方法里面做的任何操作,和a、b已经没有任何关系了
  4. 最终输出的还是10和20
    在这里插入图片描述

5. 集合

1. Comparable 和 Comparator

  1. Comparabel接口(内部比较器),java.lang包下,有个一个compareTo(Obj)方法来排序,比较Obj和this(内部的自己)谁大
  2. Comparator接口(外部比较器),java.util包下,有一个compare(Obj1,Obj2)方法来排序,比较Obj1和Obj2谁大
  3. 一般对集合自定义排序,需要重写compareTo或compare方法,当我们需要对集合实现两种排序方式,比如一个song对象中歌名和歌手名分别采用一种排序方式的话,我们可以重写compareTo方法和使用自制的Comparator方法,或者两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort()
  4. 假设num1 = 10;num2=20;如何比较他俩谁大呢?num1-num2>0,表示num1>num2。如果=0,表示他俩一样大,如果<0表示num2比num1大
  5. 那么上面两个数比较当然好比较,但是换成对象呢?该如何比较两个对象谁大谁小呢?这就需要你用这两个接口为对象定制比较规则(同样,返回值>0,表示num1>num2…)
  1. 下面分别介绍Comparable和Comparator的用法,以及如何对集合正确排序
  1. Comparable需要让对象实现Comparable接口,集合排序时Collections.sort(list);会自动调用对象重写的compareTo()
  2. Comparator直接用匿名内部类实现即可,将两个需要排序的对象给它,集合排序,Collections.sort(list,new Comparator())即可
  1. Comparabel接口(内部比较器),实现更简单, Comparator接口(外部比较器)更灵活
import java.util.*;

public class Test implements Comparable<Test>{
    private Integer age;

    public Test(Integer age) {
        this.age = age;
    }

    /**
     * 返回一个int值,正数表示自己(this)比o大,0表示this=o2,负数表示this小于o2
     */
    @Override
    public int compareTo(Test o) {
        //根据年龄决定谁大
        return this.age-o.age;
    }

    @Override
    public String toString() {
        return "Test{" +
                "age=" + age +
                '}';
    }

    public static void main(String[] args) {
        Test test = new Test(1);
        Test test1 = new Test(2);
        ArrayList<Test> tests = new ArrayList<>();
        tests.add(test1);
        tests.add(test);
        System.out.println("list集合排序前"+Arrays.toString(tests.toArray())+"\n\n");
        System.out.println("==========Comparable排序===========");

        int i = test.compareTo(test1);
        System.out.println("Comparable:test和test1谁大(正数表示test大,0表示相等,负数表示test1大)"+i);
        Collections.sort(tests);
        System.out.println("list集合排序后"+Arrays.toString(tests.toArray())+"\n\n");


        System.out.println("==========Comparator排序===========");
        Comparator<Test> comparator = new Comparator<Test>() {

            /**
             * 返回一个int值,正数表示o2>o1,0表示o1=o2,负数表示o2小于o1
             */
            @Override
            public int compare(Test o1, Test o2) {
                //根据年龄决定谁大
                return o2.age-o1.age;
            }
        };
        int compare = comparator.compare(test, test1);
        System.out.println("Comparator:test和test1谁大(正数表示test1大,0表示相等,负数表示test大)"+compare);
        Collections.sort(tests, new Comparator<Test>() {
            /**
             * 返回一个int值,正数表示o2>o1,0表示o1=o2,负数表示o2小于o1
             */
            @Override
            public int compare(Test o1, Test o2) {
                return o2.age-o1.age;
            }
        });
        System.out.println("list集合排序后"+Arrays.toString(tests.toArray()));
    }
}

1. ArrayList和LinkedList 的区别是什么?

  1. 数据结构不同:ArrayList是动态数组的数据结构,LinkedList是双向链表
  2. 随机访问效率不同:ArrayList随机访问效率更高,拿到下标直接取。LinkedList是线性数据存储方式,需要移动指针依次从前往后查找
  3. 增加和删除效率不同:非首尾增加和删除,LinkedList要比ArrayList效率高,ArrayList增删操作要影响数组内其它数据下标。往中间插入,需要其它数据向后移动。LinkedList直接改前驱和后缀
  4. 内存空间占用:LinkedList相较更费内存,除了存储数据,还要存储前驱和后缀的引用
  5. 线程安全:哥俩都不同步,都线程不安全
  6. 频繁读取数据,用ArrayList,插入,删除多,用LinkedList

标签:面试题,abc,java,String,int,ArrayList,System,----,new
来源: https://blog.csdn.net/grd_java/article/details/123107595

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有