java语言基础

在这里插入图片描述
在这里插入图片描述

2.1.1. ⾯向对象和⾯向过程的区别

1.在性能方面:
面向过程的性能要好于面向对象。因为面向对象有对象的概念,需要实例化对象,这会消耗大量的资源。所以面向对象的性能差一些。

2.在可维护性,可扩展性方面:
面向对象的可维护性和可扩展性要好的多。因为面向对象有封装,继承,多态等特性,会使系统的可维护性和可扩展性更好。

java比较慢是因为:java并不是像面向过程语言编译为机器码后让机器执行,而是使用字节码.class让虚拟机去执行,所以慢一些。

2.1.1. Java 语⾔有哪些特点?

1.简单易学
2.面向对象(封装,继承,多态)
3.平台无关性(程序编译为.class文件后给虚拟机统一执行)
4.可靠,安全
5.支持多线程,可充分利用cpu资源
6.支持并且方便进行网络编程

2.1.1. 什么是JVM JDK JRE?

jvm是java虚拟机。

要运行java程序时,编译器先把**.java文件编译为.class文件(字节码文件),然后把.class字节码文件交给jvm去把它编译为机器可以执行的二进制机器码**。

具体的话是jvm的类加载器加载.class字节码文件(因为一个.java里通常有一个类的实现),然后用解释器逐行解释执行加载的.class文件

然后引入了JIT编译器(Just-in-time),即时编译器。也就是边翻译边执行。当JIT编译器第一次执行时,会把由.class文件编译成的二进制机器码保存下来。当下次需要使用时直接执行之前保存的二进制机器码

jvm的作用是:java源代码编译成.class文件后,不论交给哪个平台的jvm实现(Windows,Linux,MacOS)都能实现相同的效果。
这也是java一次编译,处处运行关键所在


jdkjava development kit,java软件开发包。它包含jre(java运行时环境),还包括编译工具(如javac)和其它工具(如javadoc文档)。

jdk可以创建和编译java程序。

jdk能开发java程序了,那也肯定也能运行java程序,所以包含jre运行时环境


jre是java runtime environment运行时环境,是运行已编译的java程序时所必备的。包括:jvm,java类库等。

jre不能创建java程序,只能运行


正常开发者装的话,直接装一个jdk就可以了,因为jdk里面包含jre,因为都能创建java程序并运行了,也就不用考虑jre的事情了。

2.1.4. OracleJDK 和 OpenJDK 的对⽐

OpenJDK是一个完全开源的JDK模型,而OracleJDK是Oracle公司对OpenJDK的一个实现,并不是完全开源的。

OracleJDK现在一直在维护和更新,所以它的很多bug已经修复了,并且进行了很多优化和添加了更多的功能
所以如果是商业用途,则推荐使用OracleJDK

2.1.5. Java 和 C++的区别?

相同点:
1.都是面向对象的编程语言,都有封装,继承和多态

不同点:
1.java是单继承,而c++可以多继承。但是java可以用接口来达到类似的效果。
2.java里不提供指针直接访问内存,而c++有。
3.java里有垃圾回收器自动收集不用的对象,有一套内存管理机制。而c++里需要手动释放内存
4.在字符串中java在末尾没有结束符的概念(因为java里都是对象对象里维护有length属性,所以知道长度,就不用结束符来标识为末尾),而在c++的字符串中最后一个结束符为’\0’

2.1.6. 字符常量(字符型常量)和字符串常量的区别?

1.形式上:
字符常量是以单引号引起来的单个字符,如’a’,'1’这种。
字符串常量是以双引号引起来的若干个字符,如"abc","x"这种。

例子: char c = ‘a’; String str = “a"或"abc”;
注意:char变量里只能有一个变字符

2.含义上:
字符常量是int型ascii码值,由intascii表换出来字符char
字符串常量是在内存(内存中的方法区)中的地址

3.一个char两个字节(int占4个字节),字符串常量则占若干字节,得从系统中输出再看

2.1.7. 构造器 Constructor 是否可被 override?

构造器不能被@Override(重写),构造器只能被overload重载。

2.1.8. 重载和重写的区别

重载(overload)是在一个类中方法名相同,但是参数列表不同。
比如:无参的构造方法有一个参数和多个参数的构造方法,还有方法名一样,但是参数个数或类型不同的方法,这种现象叫重载

重写(override)是子类继承父类后,要修改父类方法中的实现。但是方法名和参数不能改变

重写方法的限制比较多,为“两不变两小一范围大”:
1.方法名和参数列表不能变
2.返回值类型抛出的异常,得小于等于父类方法。
3.方法的修饰范围大于等于父类方法。

2.1.9. Java ⾯向对象编程三⼤特性: 封装 继承 多态

封装:
就是把对象的属性设置为私有然后隐藏起来,并向外界提供专门访问该属性的方法,从而把属性的细节内聚在该对象内部

继承:
就是子类可以获得父类的所有属性和方法(父类私有属性和方法也获得,但是不能访问)在之前类的基础上进行功能的修改等,很方便的实现代码的复用

继承注意:
1.子类获得父类所有的属性和方法,父类私有的属性和方法也获得,但是不能访问
如果实在想访问父类的私有属性,可以通过父类向外部提供的get方法来访问。
2.子类可以添加自己独有的属性。
3.子类继承父类的方法可以重写,以自己的方式来实现功能。

多态:
多态就是多种形态,即父类的属性和方法在子类中有不同的形态。来增加系统的灵活性。

可以声明引用类型为父类类型,但是创建子类对象。这种情况只有在执行时才能让jvm确定

多态的实现有:继承接口式编程
继承是重写父类方法,接口是实现接口的方法。都有多种不同形态

作用:可以增加系统的灵活和可扩展性

2.1.10. String StringBuffer 和 StringBuilder 的区别是什么?String 为什么是不可变的?

1.从可变性的角度:
String是不可变的,而StringBuilder和StringBuffer是可变的。

2.从线程安全性的角度:
String是不可变的,是常量,所以线程安全
StringBuilder是线程不安全的,而StringBuffer是线程安全的。(StringBuffer里每个方法都加了synchronized关键字
StringBuffer和Hashtable实现线程安全的方式一样。

3.从性能角度:
当String初始化完后,每再创建一个String。会新开辟一个String内存对象,然后把该String引用指向该对象
所以如果有大量字符串操作时,不用String方式
而StringBuilder和StringBuffer只会操作它们对象本身,因为它们是可变的StringBuffer又因为要加锁保证线程安全,所以StringBuffer要比StringBuilder慢,但是StringBuffer比StringBuilder只慢了10%~15%。根据具体情况使用。

适用情况:
1.少量字符串操作可以用String
2.大量字符串操作但是不需要线程安全,用StringBuilder。
3.大量字符串操作但是需要线程安全,用StringBuffer。

为什么String是不可变的,而StringBuilder和StringBuffer是可变的?

因为String类里值的属性为final value[],它前面加了final关键字,表明该变量是常量只能初始化一次,然后就不能改变了

而StringBuilder和StringBuffer它们里面还没有值的属性,它们继承了AbstractStringBuilder类,它们真正值的属性是在AbstractStringBuilder父类里的。为value[],前面没有final关键字,所以它是可变的

2.1.11. ⾃动装箱与拆箱

装箱:把基本类型自动转化为对应的包装类型
拆箱:把包装类型自动转化为对应的基本类型

javap反编译.class自动装箱和拆箱的字节码文件得到底层实现方式

自动装箱和拆箱的底层实现
自动装箱是用包装类里的valueOf()静态方法实现的,自动拆箱是用把包装类里的xxxValue()的成员方法实现的。如Integer用的是intValue(),Character用的是charValue()

相关面试题:
1.[-128,127]问题

public class Main {
    public static void main(String[] args) {
        //自动装箱,用的valueOf()
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;

        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}

答案:
true
false

说明i1与i2是同一个地址,同一个对象。而i3和i4不是同一个对象。

分析:
代码是先自动装箱,用的是valueOf()
看源码:
在这里插入图片描述
在Integer包装类中有一个静态内部类IntegerCache。它里面的low和high是静态常量(初始化后就不能修改了),low直接初始为-128,而hgih可以通过配置修改,默认是127。所以就是[-128,127]。

自动装箱后100是在这个范围里,所以直接用的是提前创建的缓存(cache[]是Integer数组),所以是同一个地址,同一个对象,==返回true
而200不在这个范围内,所以创建了不同的对象,地址不同,所以==返回false。

2.总结:
只有Double和Float不缓存,剩下的包装类都缓存。

因为浮点数不是有限的,没办法缓存。所以就不缓存了。

Boolean:

public class Main {
    public static void main(String[] args) {
        //自动装箱,用的valueOf()
        Boolean b1 = false;
        Boolean b2 = false;
        Boolean b3 = true;
        Boolean b4 = true;

        System.out.println(b1==b2);
        System.out.println(b3==b4);
    }
}

结果:true
true

在这里插入图片描述

这创建的都是Boolean类型的常量,而且已经被初始化了(final修饰引用类型表示引用不可变),所以创建的都是同一个对象

2.比较一下Integer i = new Integer(xxx);和Integer i = xx;的区别?
一:一个会触发自动装箱,一个不会(自动装箱底层用的是包装类的valueOf方法)
二:自动装箱的方法一般情况下比new方式效率更高。(因为对应包装类的valueOf方法实现做了优化,比如用了缓存之类的)

3.如果像a+b这种,则会先进行自动拆箱,计算出值
如果拿值和a+b比较的话,就都返回true,因为是值和值进行比较
如果用对象.equals(a+b)的话,算完值后还要进行自动装箱,还需要看equals的具体实现(应该是同一个包装类,值相等时就返回true)。

2.1.12. 在⼀个静态⽅法内调⽤⼀个⾮静态成员为什么是⾮法的?

因为静态的方法只能用类来调用静态的方法和变量不属于任何一个对象,而是属于该类本身)。
如果是类调用的话,静态方法里面就不能出现其他非静态成员了。

2.1.13. 在 Java 中定义⼀个不做事且没有参数的构造⽅法的作⽤

也就是问声明无参的构造方法作用

如果不声明的话,代码编通不过

子类调用它的构造方法时如果没有显示用super()调用父类的构造方法,则会调用父类的无参的构造方法

但是java中当声明了有参的构造方法后,原本默认生成的无参的构造方法就不会被创建了。所以这就是为什么要声明无参构造方法的作用,因为不声明的话代码编译通不过

2.1.14. 接⼝和抽象类的区别是什么?

抽象类(用abstract修饰的类)不能被实例化,剩下跟别的一般的类没什么区别。
抽象方法(用abstract修饰的方法)抽象方法一定在抽象类中,而且不能有实现,只能在继承它的子类中去实现

1.接口里的方法都是public的,而抽象类中的不一定。而且接口中的方法一般没有实现,但是抽象类中可以有实现
2.接口里只能有常量(public static final),而抽象类中不一定。
3.一个类可以实现多个接口,但是只能继承一个抽象类

2.1.15. 成员变量与局部变量的区别有哪些?

1.从语法上看,成员变量可以被访问修饰符,如private等修饰,但是局部变量是在方法体或参数列表中,它们没有访问修饰符去修饰

2.从储存位置上来看,成员变量是属于对象的,所以成员变量和对象一起都存放在堆中。(而static变量属于类本身,static变量存储在方法区)。而局部变量是存放在虚拟机方法栈或本地native方法栈当中的。

3.成员变量如果没有赋初值,则会赋给默认值final修饰的成员变量必须显示的赋默认值)。但是局部变量不会给它赋默认值

2.1.16. 创建⼀个对象⽤什么运算符?对象引用存储在哪?对象实体与对象引⽤有何不同?

用new运算符。
如果对象引用成员变量,则随该对象存放在里。如果对象引用局部变量,则存放在虚拟机方法或本地native方法栈当中。

1个对象引用可以指向0个或1个对象实体;1个对象实体可以被n个对象引用指向。

2.1.17. 什么是⽅法的返回值?返回值在类的⽅法⾥的作⽤是什么?

方法的返回值是方法结束返回的结果
作用是:可以得到方法计算后的结果

2.1.18. ⼀个类的构造⽅法的作⽤是什么? 若⼀个类没有声明构造⽅法,该程序能正确执⾏吗? 为什么?

类的构造方法的作用:能够创建出该类的对象,因为创建该对象时需要调用该类的构造方法。
可以正确执行。当一个类什么都没有声明时,它会自动创建默认的构造方法(无参)

2.1.19. 构造⽅法有哪些特性?

1.构造方法方法名与类名相同
2.没有返回值
3.不用手动调用,会自动调用

2.1.20. 静态⽅法和实例⽅法有何不同?

1.调用方式不同。
静态方法可以用类名.test()调用,也可以创建出对象.test()调用。但是实例方法只能创建出对象后调用。
2.静态方法里面只能调用静态的变量和方法,而实例方法都可以。

2.1.21. 对象的相等(equlas())与指向他们的引⽤相等,两者有什么不同?

对象的相等,用equals()判断,判断的是对象中内容是否相等
而引用的相等,用==判断,判断的是地址是否相等

2.1.22. 在调⽤⼦类构造⽅法之前会先调⽤⽗类没有参数的构造⽅法,其⽬的是?

给子类初始化。

因为子类继承父类后,子类就有了很多父类的变量,所以要先调用父类的构造方法去帮子类初始化

2.1.23. == 与 equals(重要)

equals() 如果没有被重写的话,底层调用的是==,用来判断是不是同一个对象,对象的地址是不是相等的。
如果被重写的话,一般是判断对象中的内容是否相同,得看具体实现。

==判断是不是同一个对象,对象的地址是不是相等的。

2.1.24. hashCode 与 equals (重要)

1.什么是hashCode,有什么用?
hashCode()是Object类的一个native方法,使用c/c++实现,以内存地址来返回一个int数值。
这个hashCode一般用在
哈希表
上,hashCode用来确定在哈希表上的位置(下标)。除了哈希表之外没有什么用。
在这里插入图片描述
为什么equals()和hashCode()之间有关系?
它们之间需要有一个统一性。这个统一性是官方规定的。

2.为什么重写equals()后一定要重写hashCode()?
因为官方要求为:equals()返回true时,hashCode()返回的int值必须相等
在这里插入图片描述
但如果不重写hashCode()的话,返回的内存地址生成的int值,这样hashCode()始终不会相等。所以为了满足官方要求,重写equals()后必须重写hashCode()保证当equals()相等时,hashCode()返回的int也相等

3.为什么两个对象有相同的 hashcode 值,它们也不⼀定是相等的?
因为不同的对象的hashcode值可能相等。因为重写了hashCode()方法,所以可能相等。
如果没有重写hashCode()方法,则不同对象的hashcode值一定不相等。但一般类实现都重写hashCode()方法了。

2.1.25. 为什么 Java 中只有值传递?

java的引用传递的本质也是值传递

因为把引用作为参数传递到方法后,只是把该引用作为副本复制过去了(值传递),但是并没有改变该引用的指向

2.1.28. 关于 final 关键字?

final关键字可以修饰变量,方法,类。
1.修饰变量。表示该变量是常量
如果是基本类型则初始化后值就不能再被改变,如果是引用类型则初始化后引用不能再被更改

2.修饰方法。表示该方法不能被子类覆盖/重写
如果父类的方法为private,则默认隐式地加上了final。(因为子类要重写时该private方法对它不可见,就没办法重写,也就相当于加上了final)。

3.修饰类。修饰类表示该类不能被其他类继承

2.1.29. Java 中的异常处理

有一个Throwable父类,Exception和Error都是继承该Throwable父类的子类。
Exception是可以自己去处理的(比如抛出throws,或处理try…catch…finally),而Error是无法处理的(只能去避免)。
在这里插入图片描述
而异常Exception又分为需要检查的异常(check Exception)和不需要检查的异常(uncheck Exception)。

需要检查的异常出现时,必须去处理(抛出,或捕获),否则无法运行。
不需要检查的异常出现时,就不一定要处理就可以去运行

在这里插入图片描述

除了RuntimeException及其子类非检查异常外,剩下IOException,SQLException之类的都是检查异常

因为RuntimeException里面有空指针异常,数组下标越界异常,(运行时异常检查不出来)都是不需要检查的。

try…catch…finally…用法:
执行到try里时,如果没有抛出异常就把try中执行完,然后执行finally里的代码。如果抛出异常了,就到对应的catch里处理异常,处理完后再从try里该句后面继续执行。最后都会到finally里去执行。

如果用了System.exit(0),就不会执行finally里的语句了。

注意:
当try和finally都有return时,在try里return会转到finally里执行,最后finally里的return会把try里的覆盖

2.1.30. Java 序列化中如果有些字段不想进⾏序列化,怎么办?

对变量使用transient关键字,这样在序列化中这个变量就不会进行序列化了。

2.1.31.获取⽤键盘输⼊常⽤的两种⽅法

1.Scanner 2.BufferReader

2.1.32.1. Java 中 IO 流分为⼏种?

照流向可分为:输入流和输出流(输入流是读,输出流是写)
操作单元可分为:字节流和字符流。
按照流是否与某个地方(节点)相连来划分:节点流和处理流

节点流:流向或者从某个节点读写数据
处理流:对已经存在的流进行连接和封装,并读写数据。

2.1.32.2.既然有了字节流,为什么还要有字符流?

字符流是可以由字节流转化来的。

是因为如果要处理字符时,字节流转化为字符特别费时间和麻烦,并且要考虑字符的编码等相关的问题,而字符流又经常使用,所以就直接把字符流单独作为了一个部分,从而提高使用字符流的效率

处理文件,图片等用字节流处理字符字符流

2.1.32.3. BIO,NIO,AIO 有什么区别?

I/O用来进行数据的读取和写入

BIO:是Blocking I/O的缩写。是同步阻塞IO
数据的读取和写入必须阻塞在一个线程里。适用于并发量不是很大的地方。(性能不好,但是实现简单)

NIO:是Non-Blocking I/O的缩写,是同步非阻塞IO
数据的读取和写入不必阻塞在一个线程中。适用于并发量很大的地方。(性能好,但实现复杂一些)

AIO:是ASynchronized I/O的缩写,是异步非阻塞IO
异步就是线程操作结束后就返回,等需要调用它时它才过来
这个用的不多

2.1.33. 深拷⻉ vs 浅拷⻉

对应基本数据类型都是把值进行拷贝,没有区别。

引用类型拷贝有区别:

浅拷贝:就是只拷贝一个引用并把这个引用指向原来的对象实体。(并没有拷贝对象实体
深拷贝:就是不仅把引用拷贝了一个,而且把对象实体也拷贝了一份让新引用指向了新拷贝的对象实体

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值