Java知识回忆录(一)——Java基础

  1. Java中的基本数据类型。8种基本数据类型,整型:byte(8位),short(16位),int(32位),long(64位);浮点型:float(32位),double(64位);字符型:char(2个字节,16位);布尔型:boolean(存储空间计量单位为字节不是位,所以boolean虽然是1位但是占一个字节,JVM规范中boolean变量当做int处理,boolean数组当做byte数组处理(每一个元素占一个字节))。(tips:引用数据类型:类,接口,数组)
  2. String类能否被继承?为什么?  String类被final修饰,所以不能被继承(表明这个类不能被继承。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。)。final修饰方法,表示方法不能被重写(明确禁止该方法在子类中被覆盖的情况下才将方法设置为final。);final修饰变量表示变量不能被改变。(对于被final修饰的变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。虽然不能再指向其他对象,但是它指向的对象的内容是可变的。类似数组和list)注:一个类中的private方法会隐式地被指定为final方法。
  3. String, Stringbuffer, StringBuilder的区别。  1. String是final修饰的类,String类的内容声明之后不可改变,改变的只是其内指向的内容。(String对象不可修改指的是对象本身不可修改,而不是引用不可修改。)2.Stringbuffer代表一个字符序列可变的字符串,对于StringBuffer,不能像String那样直接通过赋值的方式完成对象实例化,必须通过构造方法的方式完成。(StringBuffer sb = new StringBuffer)。3.StringBuffer和StringBuilder相似都是可变的字符串,但是StringBuffer的方法都添加了synchronized关键字,给方法添加锁,保证线程安全,所以StringBuffer是线程安全的,StringBuilder是非线程安全的,所以StringBuilder的效率高于StringBuffer。
  4. ArrayList和LinkedList、Vector有什么区别。  1.ArrayList和Vector底层以数组的形式实现,LinkedList则以链表的形式进行存储。2.Vector是线程同步的,LinkedList和ArrayList是线程不同步的3.由于底层实现方式不同,ArrayList和Vector进行查找小路高,而LinkedList进行删除,插入的效率高。(拓展List、Set、Map之间的区别和联系。参照该链接:https://blog.csdn.net/weixin_42504145/article/details/83119088)。
  5. 类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序。    先静态再父子

    父类静态代变量、 
    父类静态代码块、 
    子类静态变量、 
    子类静态代码块、

    父类非静态变量(父类实例成员变量)、 
    父类构造函数、 
    子类非静态变量(子类实例成员变量)、 
    子类构造函数。

  6. 用过哪些Map类,都有什么区别,HashMap是线程安全的吗,并发下使用的Map是什么,他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。     HashMap、HashTable、LinkedHashMap、TreeMap。HashMap不是线程安全的,并发下使用ConcurrentHashMap,HashMap采用数组+链表+红黑树(JDK8加入)的实现方式。参照该链接:https://zhuanlan.zhihu.com/p/21673805    

  7. JAVA8 的 ConcurrentHashMap 为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。 

    jdk8 放弃了分段锁而是用了Node锁,减低锁的粒度,提高性能,并使用CAS操作来确保Node的一些操作的原子性,取代了锁。

    但是ConcurrentHashMap的一些操作使用了synchronized锁,而不是ReentrantLock,虽然说jdk8的synchronized的性能进行了优化,但是我觉得还是使用ReentrantLock锁能更多的提高性能

     参照:https://yq.aliyun.com/articles/36781

  8. 有没有顺序的Map实现类,如果有,他们是怎么保证有序的。

    TreeMap和LinkedHashMap是有序的(TreeMap默认升序,LinkedHashMap则记录了插入顺序)。

    参照:http://uule.iteye.com/blog/1522291

  9. 抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么。     接口是特殊的抽象类

         1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。 

         2、抽象类要被子类继承,接口要被类实现。  

         3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现 

         4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量可以是普通变量。 

         5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。 

         6、抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。 

         7、抽象类里可以没有抽象方法 。

         8、如果一个类里有抽象方法,那么这个类只能是抽象类 。

         9、抽象方法要被实现,所以不能是静态的,也不能是私有的。 

        10、接口可继承接口,并可多继承接口,但类只能单根继承。

   10.继承和聚合的区别在哪。   继承是一个类继承另一个类的属性和方法,并允许自己扩展。(b is a的关系用extends标识)。聚合是整体与部分、拥有的关系。组合是强聚合

    11.IO模型有哪些,讲讲你理解的NIO,他和BIO,AIO的区别是什么,谈谈reactor模型。谈谈NIO和IO的区别。

1.什么是BIO,NIO,AIO
       JAVA BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程并处理,如果这个连接不做任何事情会造成不必要的开销,当然可以通过线程池机制改善
       JAVA NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理
       JAVA AIO(NIO2):异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理  

参考链接:https://blog.csdn.net/weixin_42656794/article/details/90700595                                    Reactor模型理解:https://blog.csdn.net/qq330983778/article/details/88061304

12.反射的原理,反射创建类实例的三种方式是什么。

反射的原理:

   1. 反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;

    2. 每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;

    3. 反射也是考虑了线程安全的,放心使用;

    4. 反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;

    5. 反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;

    6. 当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;

    7. 调度反射方法,最终是由jvm执行invoke0()执行;

反射创建实例的三种方式。1.Person.class;2.Person.getClass();3.Class.forName();

参考链接:https://blog.csdn.net/riemann_/article/details/86766915

13.反射中,Class.forName和ClassLoader的区别。  类的装载过程。加载-链接-初始化-使用-卸载(链接包含,验证,准备,解析)

forName会将类加载到JVM中,同时会对类进行解释,执行类中的静态代码块static块

ClassLoader只会将类加载到JVM,不会执行static中的内容,只有在newInstance才会去执行static块。

数据库链接为什么使用Class.forName(className)

参考链接:http://baijiahao.baidu.com/s?id=1654865863100987859&wfr=spider&for=pc

14.描述动态代理的几种实现方式,分别说出相应的优缺点。  (数据库的事物包裹调用例子)

代理可以分为 "静态代理" 和 "动态代理",动态代理又分为 "JDK动态代理" 和 "CGLIB动态代理" 实现。

静态代理:代理对象和实际对象都继承了同一个接口,在代理对象中指向的是实际对象的实例,这样对外暴露的是代理对象而真正调用的是 Real Object

  • 优点:可以很好的保护实际对象的业务逻辑对外暴露,从而提高安全性。
  • 缺点:不同的接口要有不同的代理类实现,会很冗余

JDK 动态代理

  • 为了解决静态代理中,生成大量的代理类造成的冗余;
  • JDK 动态代理只需要实现 InvocationHandler 接口,重写 invoke 方法便可以完成代理的实现,
  • jdk的代理是利用反射生成代理类 Proxyxx.class 代理类字节码,并生成对象
  • jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口

  • 优点:解决了静态代理中冗余的代理实现类问题。
  • 缺点:JDK 动态代理是基于接口设计实现的,如果没有接口,会抛异常。

CGLIB 代理

  • 由于 JDK 动态代理限制了只能基于接口设计,而对于没有接口的情况,JDK方式解决不了;
  • CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,来完成动态代理的实现。
  • 实现方式实现 MethodInterceptor 接口,重写 intercept 方法,通过 Enhancer 类的回调方法来实现。
  • 但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
  • 同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

  • 优点:没有接口也能实现动态代理,而且采用字节码增强技术,性能也不错。
  • 缺点:技术实现相对难理解些。

动态代理在Java中有着广泛的应用,比如Spring AOP、Hibernate数据查询、测试框架的后端mock、RPC远程调用、Java注解对象获取、日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等。

代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。

tips:

  • 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
  • 而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件

参考链接:https://www.cnblogs.com/whirly/p/10154887.html

15.动态代理和cglib代理实现的区别。

jdk动态代理,基于接口实现,没有接口的情况无法实现。采用java类反射的机制,创建代理实例速度快,但是运行方法速度不如cglib。

cglib:对指定的目标类生成子类,并覆盖其中的方法实现增强。但是不能代理final类。创建代理类实例时花费较大,速度慢。但是运行方法时速度快,性能高。适用于对单例类代理。

16.为什么cglib方式可以对接口实现代理。

cglib动态代理是通过继承并重写目标类来实现的,而接口是可以被继承的。所以可以实现

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

17.final的用途

1.final修饰引用。修饰基本数据类型,则该引用为常量,值无法被改变。修饰引用数据类型,比如对象、数组,则该对象或数组本身可以改变,但是指向该对象或数组的地址的引用不能修改。

2.修饰方法。表示该方法不能被重写。

3.修饰类。表示该类为最终类,不能被继承。String。

18.写出三种单例模式的实现。

单例模式:基于某种方法实列化多次得到的实例是同一个。当实例化多次得到的对象中存放的属性都一样的情况下,应该将多个对象指向同一个内存,即同一个实例(实例化同样的对象,通过单例模式,可以降低内存的暂用)

设计模式参考:https://www.cnblogs.com/xuwendong/p/10078571.html

19.如何在父类中为子类自动完成所有的hashcode和equals实现?这么做有何优劣?

父类的equals不一定满足子类的equals需求。比如所有的对象都继承Object,默认使用的是Object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。

但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们要重写equals方法。

如果重写了equals 方法就必须重写hashcode方法,否则就会降低map等集合的索引速度。

20.请结合OO设计理念,谈谈访问修饰符public,protected,default,private在应用设计中的作用。

OO设计理念:封装、继承、多态、

java访问控制符的含义和使用情况。PPDP   外部包、子类、本包、本类

21.深拷贝和浅拷贝的区别。

深拷贝和浅拷贝针对引用数据类型,如对象,数组等。浅拷贝只是复制了一个引用对象并没有复制引用对象指向的内容,当指向的内容改变时,浅拷贝也会随之改变。深拷贝是复制了引用对象,并且复制了对象指向的堆内存中的内容。深拷贝实现方式:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝

参考https://segmentfault.com/a/1190000018874254https://segmentfault.com/a/1190000018874254

22.数组和链表数据结构描述,各自的的时间复杂度。

数组,内存连续,提前申请好固定内存,内存利用率低,存放在栈内存,随机访问效率高O(1),在起始位置添加和删除的时间复杂度为O(n)

链表,内存分散,随机,动态申请内存,内存利用率高,存放在堆内存,随机访问效率低O(n),在任意位置添加和删除的时间复杂度为O(1)

参考链接:https://blog.csdn.net/dangzhangjing97/article/details/81699050

23.error和exception的区别,CheckedException,RuntimeException的区别。

Error(错误)表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题。比如:内存资源不足等。对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由Java虚拟机抛出的。
    Exception(违例)表示需要捕捉或者需要程序进行处理的异常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。
Exception又分为运行时异常,受检查异常。
       RuntimeException(运行时异常),表示无法让程序恢复的异常,导致的原因通常是因为执行了错误的操作,建议终止程序,因此,编译器不检查这些异常。
       CheckedException(受检查异常),是表示程序可以处理的异常,也即表示程序可以修复(由程序自己接受异常并且做出处理), 所以称之为受检查异常。

参考链接:https://mp.csdn.net/console/editor/html/104519710

24.请列举5个运行时异常。

NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException、ClassNotFoundException、ArrayStoreException、

25.在自己的代码中,如果创建一个java.lang.String类,这个类是否可以被类加载器加载?为什么?

不可以,双亲委派模式会保证父类加载器先加载类,就是BootStrap(启动类)加载器加载jdk里面的java.lang.String类,而自定义的java.lang.String类永远不会被加载到

参考链接:https://blog.csdn.net/weixin_38055381/article/details/80167881

26.说一说你对java.lang.Object对象中的hashCode和equals方法的理解,在什么场景下需要重写这2个方法?

 

27.在jdk1.5中,引入了泛型,泛型的存在是用来解决什么问题?

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率

28.这样的a.hashcode()有什么用,与a.equals(b)有什么关系?

hashcode
hashcode()方法提供了对象的hashCode值,是一个native方法,返回的默认值与System.identityHashCode(obj)一致。

通常这个值是对象头部的一部分二进制位组成的数字,具有一定的标识对象的意义存在,但绝不定于地址。

作用是:用一个数字来标识对象。比如在HashMap、HashSet等类似的集合类中,如果用某个对象本身作为Key,即要基于这个对象实现Hash的写入和查找,那么对象本身如何实现这个呢?就是基于hashcode这样一个数字来完成的,只有数字才能完成计算和对比操作。

hashcode是否唯一
hashcode只能说是标识对象,在hash算法中可以将对象相对离散开,这样就可以在查找数据的时候根据这个key快速缩小数据的范围,但hashcode不一定是唯一的,所以hash算法中定位到具体的链表后,需要循环链表,然后通过equals方法来对比Key是否是一样的。

equals与hashcode的关系
equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。

29.有没有可能2个不相等的对象有相同的hashcode。

1)对于equals()与hashcode(),比较通用的规则:
            ①两个obj,如果equals()相等,hashCode()一定相等
            ②两个obj,如果hashCode()相等,equals()不一定相等

有可能,最简单的方法,百分百实现的方式就是重写hascode();

30.java中的HashSet内部是如何工作的。

底层是基于hashmap实现的

31.什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。

序列化是一种用来处理对象流的机制 ,所谓对象流就是将对象的内容进行流化。

序列化是为了解决在对对象流进行读写操作时所引发的问题。

序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流;

32.java8的新特性。

https://www.jianshu.com/p/0bf8fe0f153b

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值