• Java不会或做错的面试题总结


    1. 八种基本数据类型的封装类及其大小(字节)

    答:byte Byte 1

    short Short 2

    int Integer 4

    long Long 8

    float Float 4

    double Double 8

    char Character 2

    boolean Boolean - (boolean是JVM没有的数据类型,根据《Java虚拟机规范》,boolean会被JVM编译成int数据类型来代替,boolean数组则会被JVM编译成byte数组,每个boolean占8位,所以boolean单独使用是占4字节,而用boolean数组则每个boolean占1字节)

    那JVM为什么要用int来代替boolean呢,用byte或short不是更节省内存空间吗?其实用int的原因是对于当下32位的CPU来说(这里是指32/64位系统,而是指CPU硬件层面),具有高效存取的特点

    2.这题做错了,贴正确答案的理解出来

    1         //int y = x++ + ++x; 先是x++为4,然后完成这一步就变成5了,然后++x为6,所以y为10
    2         //如果是int y = ++x + x++;结果也为10,但是过程不一样:先是++x为5,然后x++也为5
    3         int x = 4;
    4         int y = x++ + ++x;//y=4+6=10,最后x的值为6
    5         System.out.println(++x + y + x++);//7+10+7=24,所以打印出的值为24

    3.==与equals的区别

    i. 一般用==比较基本数据类型,用equals比较对象

    ii. ==判断两个变量或者实例是不是指向同一个内存空间,是对内存地址进行比较;而equals判断两个变量或者实例指向的内存空间的值是否相同

    iii. 简单来说就是==判断引用是否相同,equals判断值是否相同

    4. A类有个x方法,B类继承A类,B类的x方法的访问修饰符(private, public这些)能改变吗?要怎么改?

    答:只能向更可见的方向改,比如,A类的x方法是protected修饰的,那B类的x方法就只能是public,因为要避免父类方法可见而子类却不可见

    5. A类有个x方法throw出异常,B类继承A类并重写了x方法,请问要throw怎样的异常?

    答:只能向下throw,也就是throw A类x方法的异常的子类,比如A的x方法throw Exception,B的方法throw InterruptedException。这是因为编译器要求调用子类方法的时候捕捉的是父类方法的异常,所以如果B的x方法throw的异常是A异常的父类,那就捕捉不了A的x方法的异常了

    6. public, protected, default, private这几个访问修饰符的区别

    答:public : “公共的”,所有其修饰的类、属性和方法能被所有类访问(同类,同包不同类,不同包的子类,不同包的非子类)

    protected: “保护形”,其修饰的类、属性和方法可被(同类,同包不同类,不同包的子类)访问,不可被(不同包的非子类)访问

    default: “默认访问模式”,其修饰的类、属性和方法可被(同类,同包不同类)访问,不可被(不同包的子类,不同包的非子类)访问

    private: “私有的”,其所修饰的类、属性和方法仅可被该类的对象访问,其他类要访问private的属性要用getter, setter方法

    7. 初始化的顺序(这一题他是给了代码,B类继承A类,然后主方法里new了两个B类,问会打印出什么)

    答:父类静态属性(只会调用一次)>父类静态代码块(只会调用一次)>子类静态属性(只会调用一次)>子类静态代码块(只会调用一次)

    >父类非静态代码块>父类构造器>子类非静态代码块>子类构造器

    8. (具体数字忘了但我写个大概)1.x.x.0 ~ 1.x.x.255 是广东的IP,2.x.x.0~2.x.x.255是福建的IP,设计一个方法来验证输入的IP是哪个地区的

     1 public static String searchIP(String ip){
     2         String[] strs = ip.split("\.");
     3         int[] nums = new int[4];
     4         for (int i = 0; i < nums.length; i++) {
     5             nums[i] = Integer.valueOf(strs[i]);
     6         }
     7         if (nums[0] == 1){
     8             if (nums[1] == 0 && nums[2] == 0 && 0 <= nums[3] && nums[3] <= 255){
     9                 return "广东";
    10             }
    11         }
    12         else if(nums[0] == 2){
    13             if (nums[1] == 1 && nums[2] == 1 && 0 <= nums[3] && nums[3] <= 255){
    14                 return "福建";
    15             }
    16         }
    17         return null;
    18     }

     9. 一个类里有synchronized的A方法和synchronized的B方法,现在new了两个实例,并且有两个线程,一个线程中其中一个实例使用A方法,另一个线程中另一个实例使用B方法,可以吗?

    答:可以的。synchronized一个非静态方法实际上等于synchronized一个实例,而现在这两个实例是没有关系的,所以他们各自在线程中使用A或B方法是没有影响的。

    10. 一个类里有synchronized的静态A方法和synchronized的静态B方法,现在new了两个实例,并且有两个线程,一个线程中其中一个实例使用A方法,另一个线程中另一个实例使用B方法,可以吗?

    答:不可以。synchronized一个静态方法实际上等于synchronized这个类对象,所以两个线程里的两个实例同时访问同步了的静态方法是不行的。

    11.你会哪些SQL语句调优?什么是索引失效?

    答:1.尽量避免全表扫描,应考虑在where及order by涉及的列上建立索引。对于频繁需要查询的列建立索引,而对于频繁需要insert, update和delete的列最好别使用索引

    2. 避免在where子句中进行null值判断,否则导致引擎放弃使用索引而进行全表扫描

    3. 避免在where子句中使用!=或<>操作符,否则导致引擎放弃使用索引而进行全表扫描

    4. 避免在where子句中使用or来连接条件,否则导致引擎放弃使用索引而进行全表扫描,如

    SELECT id FROM table WHERE num = 10 OR WHERE num = 20可改为

    SELECT id FROM table WHERE num = 10

    UNION ALL

    SELECT id FROM table WHERE num = 10

    5. 避免用in 和not in,,否则导致引擎放弃使用索引而进行全表扫描

    对于连续的数值,能用between就别用in,如:

    SELECT id FROM table WHERE num IN (6, 7, 8)改为

    SELECT id FROM table WHERE num BETWEEN 6 AND 8

    6. 如果在模糊搜索关键字前加%,将导致引擎放弃使用索引而进行全表扫描,如

    SELECT id FROM table WHERE name LIKE '%ky'

    如果%放在后面SELECT id FROM table WHERE name LIKE 'ky%'则还是会用索引

    7. 避免在where子句中对字段进行函数操作,否则导致引擎放弃使用索引而进行全表扫描,如

    SELECT id FROM table WHERE age / 2 = 10,应改为

    SELECT id FROM table WHERE age = 20

    8. 避免在有大量重复数据的列上建立索引,这样SQL可能不会用到索引,即使用索引也对查询效率起不了提升

    12. 往ArrayList和LinkedList后面不断插入数据,谁更快?

    答:这个时候就要感谢我的面试官了,他提供了很专业的解答,使我受益匪浅。插入数据量少的时候,ArrayList更快,多的时候LinkedList更快。ArrayList是动态数组,插入的时候会进行两倍的扩容,然后把旧数组的数据复制到新数组里面,而到了后面插入的数据很多时(比如说1000万),扩容和复制的时间会越来越大。而LinkedList插入数据的实现原理是新建一个Node,然后把某数据的指针指向它,而新建这个Node对象是要花费不少时间的。所以总的来说,插入数据量少的时候,ArrayList更快,否则则LinkedList更快

    13. SpringCloud和Dubbo的远程调用机制有什么不同?

    答:Dubbo的远程调用是基于RPC的,SpringCloud的远程调用是基于RESTful的。区别在于传输协议中,RESTful是基于HTTP的,而RPC是基于自定义TCP协议的,对比起HTTP协议精简了许多。因为HTTP即使报文body是用二进制编码的,但报头键值对是用文本编码的,非常占字节数;而自定义TCP传输协议的报头可以用二进制来编码,精简了传输内容

    14. Spring的AOP原理是怎么实现的?

    答:Spring AOP采用的是动态代理,在运行期间对业务方法进行增强,不会产生新类

    Spring AOP提供了对JDK动态代理的支持和cglib(Code generate library)动态代理的支持。前者是基于反射的机制实现,后者是基于继承的机制实现。如果目标对象有实现接口,则使用JDK代理,否则则使用cglib代理。

    JDK动态代理:

    被代理类的接口:

    1 //1. JDK动态代理需要被代理类实现一个接口,下面就是这个接口
    2 public interface FruitOperation {
    3 
    4     public void freeze();
    5     
    6     public void fetch();
    7 }

    被代理类:

     1 //2.这是被代理类,实现了一个接口
     2 public class PeachOperation implements FruitOperation{
     3 
     4     public void freeze(){
     5         System.out.println("把桃子放入冰箱冷冻");
     6     }
     7     
     8     public void fetch(){
     9         System.out.println("把桃子从冰箱取出");
    10     }
    11 }

    写一个类来实现InvocationHandler接口,通过重写invoke方法来对被代理类的接口的方法实现增强,通过getProxy方法来产生Proxy对象:

     1 //写一个类来实现InvocationHandler接口,在该类中对被代理的方法做增强,并编写生成代理对象的方法
     2 public class FridgeJDKProxy implements InvocationHandler{
     3 
     4     //被代理的对象,也就是真实的对象,之后用反射调用被代理方法的时候需要被代理对象的引用
     5     private Object target;
     6     
     7     //InvocationHandler接口的方法
     8     //proxy是代理对象,method是被代理的方法,args是被代理方法的参数,返回值是原方法的返回
     9     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    10         //调用被代理方法做一些操作
    11         openDoor();
    12         //执行被代理对象的方法,如果方法有返回值则赋值给result
    13         Object result = method.invoke(target, args);
    14         //调用被代理方法做一些操作
    15         closeDoor();
    16         return result;
    17     }
    18     
    19     public Object getProxy(Object target){
    20         this.target = target;
    21         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    22     }
    23     
    24     public static void openDoor(){
    25         System.out.println("打开冰箱门");
    26     }
    27     
    28     public static void closeDoor(){
    29         System.out.println("关上冰箱门");
    30     }
    31 }

    测试:输出为(“把桃子放入冰箱冷冻”和“把桃子从冰箱取出”前后都分别有“打开冰箱门”和“关上冰箱门”)

     1 public class Test {
     2 
     3     public static void test(){
     4         FruitOperation f = (FruitOperation) new FridgeJDKProxy().getProxy(new PeachOperation());
     5         f.freeze();
     6         f.fetch();
     7     }
     8     
     9     public static void main(String[] args) {
    10         test();
    11     }
    12 }

    而CGLib动态代理还是非常类似的。要写一个类实现MethodInterceptor接口,并重写intercept方法(类似JDK动态代理的invoke方法)来对方法进行加强,并编写生成Proxy的方法getProxy

     

    Firstly written on October 16th, 2019

  • 相关阅读:
    [计算机故障处理]小区宽带无法上网(中国联通)
    [计算机故障]笔记本无法启动,开机启动出现“Operating System Not Found”无法进系统
    [英语学习]微软面试前英语集训笔记-day 1
    [办公应用]如何将excel合并单元格分拆后每个单元格上仍保留数据?
    [办公应用]如何设置IE打印时的默认页边距,并设置纸张为横向(会计票据打印)
    [计算机故障]excel无法存盘,总是自动重启恢复
    codeforces732D 二分加贪心。。
    topcoder-srm701-div2-900 博弈计算二进制位1的个数dp状态压缩
    什么是超级立方体,HyperCube
    从维度理解dp问题
  • 原文地址:https://www.cnblogs.com/LittleMike/p/11689003.html
Copyright © 2020-2023  润新知