Java基础

129 阅读11分钟

Java基础

1. JDK和JRE有什么区别?

  • JVM: java虚拟机,负责把.class 二进制文件翻译成不同系统上的机器操作指令
  • JRE: 包含了JVM和一些类库,如果不对代码进行编译只是运行,那么只需要jre就可以了
  • JDK: 包含了JRE和一些开发工具,如javac命令可以对java代码进行编译

2. ==和equals的区别是什么?

  • 凡是比较基本类型都只能用==,比较的结果就是眼睛能看到的字面量,基本类型只有8种,byte,short,int,long,char,float,double,记住String不是基本类型。基本类型不是对象,所以不存在使用equals比较。
  • 凡是比较引用类型(对象)的时候==和equals的使用是有区别的。==的使用是比较两个引用(对象)是不是指向同一个内存地址,equals比较的是字面量是不是一致。
  • 基本类型的包装类是对象类型,所以除非两个相同字面量的引用指向同一个内存地址,值才会相等。

3. 两个对象的hashCode()相同,则equals()也一定为true,对吗?

结论

  • 两个对象equals相等,则它们的hashcode必须相等,反之则不一定。
  • 两个对象==相等,则其hashcode一定相等,反之不一定成立。

hashCode 的常规协定

1)在 Java 应用程序执行期间,在对同一对象多次调用hashCode方法时,必须一致地返回相同的整数,前提是将对象进行equals比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
2)两个对象的equals()相等,那么对这两个对象中的每个对象调用 hashCode方法都必须生成相同的整数结果。
3)两个对象的equals()不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求一定生成不同的整数结果。但是,为不相等的对象生成不同整数结果可以提高哈希表的性能。

4. final在Java中有什么作用?

final作为Java中的关键字可以用于三个地方。用于修饰类、类属性和类方法。 特征:凡是引用final关键字的地方皆不可修改!

  • 修饰类:表示该类不能被继承;

  • 修饰方法:表示方法不能被重写;

  • 修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

    相信大家都具备基本的常识: 被final修饰的变量是不能够被改变的. 但是这里的"不能够被改变"对于不同的数据类型是有不同的含义的.

    当final修饰的是一个基本数据类型数据时, 这个数据的值在初始化后将不能被改变; 当final修饰的是一个引用类型数据时, 也就是修饰一个对象时, 引用在初始化后将永远指向一个内存地址, 不可修改. 但是该内存地址中保存的对象信息, 是可以进行修改的.

5. Java中的Math.round(-1.5)等于多少?

dMath.round(d)Math.ceil(d)Math.floor(d)
1.312.01.0
1.522.01.0
1.722.01.0
-1.3-1-1.0-2.0
-1.5-1-1.0-2.0
-1.7-2-1.0-2.0
  • Math.round(d): 四舍五入,入的时候是到大于它的整数
  • Math.ceil(d): 返沪不小于的最小整数
  • Math.floor(d): 返回不大于的最大整数

6. String属于基础的数据类型吗?

String不属于八种基本类型,它是引用类型。
  • String str = "kvill"String str = new String("kvill")的区别

    常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。

    Java会确保一个字符串常量只有一个拷贝,用new String()创建的字符串不是常量,不能再编译器就确定下来,所以new String()创建的字符串不放在常量池中,它们会被放在堆上,有自己的内存地址。

  • String.intern()

    存在于.class文件中的常量池,在运行期被JVM转载,并且可以扩充,String的intern()方法就是扩充常量池的一个方法,当一个String实例str调用intern()方式时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其引用,如果没有,则在常量池中新增一个Unicode等于str的字符串并返回它的引用。

  • 关于equals()==区别

    equals()对于String简单的来说就是比较两个字符串的Unicode序列是否相同,如果相等则返回true;而==是比较两字符串的地址是否相同,比较是不是同一个字符串的引用

  • 关于String是不可变的

7. Java中操作字符串都有哪些类?它们之间有什么区别?

StringStringBufferStringBuilder

  • StringBuffer,StringBuilder都是字符串的缓冲区、可变的字符序列,具有相同的构造方法

  • 内存,String是不可变的对象,每次操作都会生成新的String对象,然后指针指向新的String对象;StringBuffer、StringBuilder可以在原有的对象基础上进行操作,所以在经常改变字符串内容的情况下,最好不要用String

  • 出现版本,StringBuffer是Jdk1.1, StringBuilder是Jdk1.5

  • 线程安全, StringBuffer是线程安全的,同步锁(synchronized),多线程仍可以保证数据安全,StringBuilder线程不安全,多线程不能保证数据安全

  • 效率, StringBuilder > StringBuffer > String

  • 总结,不频繁增改字符,就用String, 否则用StringBuffer或StringBuilder

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

9. 如何将字符串反转?

  • 利用StringBuffer或者StringBuilder的reverse成员方法

  • 利用String的toCharArray方法先将字符串转化为char类型数组,然后将各个字符进行重新拼接

  • 利用String的CharAt方法去除字符串进行拼接

10. String类的常用方法都有哪些?

  • indexOf() 返回指定字符得索引
  • charAt() 返回指定索引处得字符
  • repalce() 字符串替换
  • trim() 去除字符串两端的空白
  • split() 分割字符串 返回分割后的字符串数组
  • getBytes() 返回字符串的byte类型数组
  • length() 返回字符串的长度
  • toLowerCase() 字符串转小写
  • toUpperCase() 字符串转大写
  • substring() 截取字符串
  • equals() 字符串比较

抽象类和接口

抽象类

  • abstract修饰的类为抽象类,此类不能被实例化
  • abstract修饰的方法为抽象方法,此方法不能有方法体
    • 抽象类不能有对象
    • 有抽象方法的类一定是抽象类,但是抽象类不一定有抽象方法
  • 抽象类中的抽象方法必须在子类中被重写

子类实现方法必须含有相同的或者更低的访问级别(public > protected > private)。抽象类的子类为父类中所有抽象方法的具体实现,否则也为抽象类。

为什么要有抽象类?有些东西不一定能是一个人写的,所有有些方法当时可能写不出来,所以写个大概。

抽象方法不饿能有方法题,在方法后面加一个大括号而里面什么也不写也不行,否则编译器会报abstract methods do not specify a body

当一个类继承抽象类时候,这个类必须去重写所有继承的抽象类的抽象方法,否则编译器会报The type Cat must implement the inherited abstract method Animal.eat()

接口

  • 接口中所有的属性默认为: public static final ***
  • 接口中所有的方法默认为:public abstract ***
  • 接口不再像类一样用关键字extends去继承,而是使用implements去实现,也就是说类和接口的关系是实现
  • 一个类可以实现多个接口,但只能继承一个类,所以可以通过这种方式是实现多继承

*抽象类和接口的区别

  • 抽象类描述的是"是不是"的问题,而接口描述的是"有没有"的问题;接口强调特定功能的实现,而抽象类强调所属关系
  • 接口只有定义,不能有方法的实现,而抽象类可以既有定义又有实现,方法可以在抽象类中实现
  • 实现接口的关键字为implements,继承抽象类的关键字为extends,一个类可以实现多个接口,但一个类只能继承一个抽象类,所以使用接口可以间接实现多继承
  • 接口的成员变量默认为public static final,必须赋初值,不能被修改;所有的成员方法public abstract。抽象类中成员变量默认default,可以在子类中被重新定义,也可以被重新赋值;抽象方法被abstract修饰,不能被private static synchronized native等修饰,必须以分号结尾,不带花括号
  • 接口被用于常用的功能,便于以后委会和添加删除,而抽象类更倾向于充当公共角色,不适用于日后重新对里面代码进行修改,功能需要累积时用抽象类,不需要累积时使用接口

11. 抽象类必须要有抽象方法吗?

12. 普通类和抽象类有哪些区别?

13. 抽象类能使用 final 修饰吗?

14. 接口和抽象类有什么区别?

15. Java中IO流分为几种?

  • 按照流的流向分,可以分为输入流和输出流;
  • 按照操作单元划分,可以划分为字节流和字符流;
  • 按照流的角色划分为节点流和处理流。

Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java IO流的40多个类都是从如下4个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。 按操作方式分类结构图 按操作对象分类结构图

16. BIO、NIO、AIO有什么区别?

  • BIO(Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的I/O并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的BIO模型是无能为力的。因此,我们需要一种更高效的I/O处理模型来应对更高的并发量。
  • NIO(New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4中引入了NIO框架,对应java.nio包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。NIO提供了与传统BIO模型中的Socket和 ServerSocket相对应的SocketChannel 和ServerSocketChannel两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用NIO的非阻塞模式来开发
  • AIO(Asynchronous I/O):AIO也就是NIO 2。在Java 7中引入了NIO的改进版NIO 2,它是异步非阻塞的IO模型。异步IO是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO是异步IO的缩写,虽然NIO在网络操作中,提供了非阻塞的方法,但是NIO的IO行为还是同步的。对于NIO来说,我们的业务线程是在IO操作准备好时,得到通知,接着就由这个线程自行进行IO操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说AIO的应用还不是很广泛,Netty之前也尝试使用过AIO,不过又放弃了。

17. Files的常用方法都有哪些?

  • Files.exists():检测文件路径是否存在。

  • Files.createFile():创建文件。

  • Files.createDirectory():创建文件夹。

  • Files.delete():删除一个文件或目录。

  • Files.copy():复制文件。

  • Files.move():移动文件。

  • Files.size():查看文件个数。

  • Files.read():读取文件。

  • Files.write():写入文件。