java基础八股(方法,面向对象,OBject,String)

这里是我自己参考javaguide总结的笔记,有些地方会有拓展,其他的我根据自己的理解来总结了

四、方法

1、什么是方法的返回值?方法有哪几种类型?

方法的返回值是方法体代码执行后产生的结果(前提是能产生结果),作用是接收到方法执行后的结果,用于其他操作。

类型:1、无参无返回值方法2、无参有返回值方法3、有参数无返回值方法4、有参有返回值方法。

2、静态方法为什么不能调用非静态成员

1、静态方法是属于类的,静态方法是在类被加载的时候就被创建了,可以直接通过类名访问。而非静态成员,是在创建实例对象时才被创建的,通过实例对象进行访问。

2、静态方法在非静态成员还未被创建的时候就已经存在了,此时调用未被创建的非静态成员变量,属于非法操作。

3、静态方法和实例方法有何不同?

1、调用的方式

静态方法可以通过类名直接调用,也可以通过实例对象名调用,但是一般用类名直接调用,防止混淆。

而实例方法只能通过实例对象进行调用。

2、访问类成员的权限

静态方法只能访问静态成员和静态方法。而实例方法没有这个限制。

4、重载和重写有什么区别?

重载:同一个类中,同名的方法根据不同的传参,执行不同的逻辑处理。(方法名必须相同,参数的个数,顺序,类型不同)

重写:子类对父类的重新改造,外部样子不变,内部处理逻辑不同,方法名相同,参数相同,子类对处理逻辑重新书写,对父类进行覆盖。(1、方法名相同,参数列表相同,但是返回值要小于或等于父类,访问修饰符要大于等于父类,抛出的异常要小于等于父类。2、对于父类中的private、final、static修饰的方法无法进行重写,对于static修饰的方法可以再次声明,构造方法无法被重写)

image-20231122110125990

方法重写遵循原则:两同两小一大

1、两同是方法名和参数列表相同

2、两小是返回值和抛出的异常比父类更小或等于

3、一大是访问修饰符比父类更大。

返回值类型如果是void或者是基本数据类型,则不变,如果是引用类型,则更小。

5、什么是可变长参数

可变长参数,是指调用方法时传入参数可以传入不定长度的参数,遇到方法重载会优先匹配固定参数的方法。java可变长参数编译后实际会转换成数组。

五、面向对象基础

1、面向对象和面向过程的区别:

面向过程是将解决问题的过程拆分为一个一个的方法,通过一个一个的方法来解决问题。

面向对象会先抽象出对象,通过调用对象中的方法来解决问题。

面向对象的性能是要低于面向过程的,因为类需要实例化,需要占用内存,因此面向过程的性能相对更高一些。

2、创建一个对象用什么运算符?对象实体与对象引用有何不同?

创建一个对象使用new运算符来创建对象。

对象实体是在堆内存中的(对象实体是实际存储在内存中的,占据一定内存空间的),而对象引用是指向对象实体的(是一个变量,用于存放对象在内存中的地址),是存放在栈中的。

对象实体可以有多个对象引用指向它,对象引用可以指向1个或者零个对象实体。

3、对象的相等和引用相等的区别

对象相等是对象在内存中存储的值相等,而引用相等是在内存中的存储地址相同。

4、如果一个类没有声明构造方法,该程序能正确执行吗?

能够正确的执行,因为系统会有一个默认的无参构造,即使一个类没有声明构造方法,当在实例化对象的时候,会调用系统默认创建的无参构造,因此能够正常执行,但是如果自己定义了有参构造,此时系统默认创建的无参构造就不存在了。因此需要自己补齐,免得吹西安一些bug。

5、构造方法有哪些特点?是否可被 override?

特点:

1、没有返回值,并且不能有void来声明构造方法

2、构造方法名跟与类名相同。

3、在创建对象的时候自动执行,无需显示的调用

构造方法不可以被重写,但是可以重载。

6、 面向对象三大特征

1)封装

封装是指将一个对象的状态信息(也就是属性)隐藏在对象的内部,不允许外部对象直接访问对象的内部信息。但是会提供一些可以被外界访问的方法来操作属性。

2)继承

继承是指使用已存在的类的定义作为基础创建新类的技术,新的类可以增加其他的数据或功能,也能使用父类的功能,但是不能选择性的继承。通过继承可以提高代码的复用性,程序的可维护性,减少创建新类的时间,提高开发的效率

由三个特点:

1、子类继承父类的所有属性和方法(包括私有属性和方法),但是对于私有属性,是拥有但是不能访问

2、子类可以拥有自己的方法和功能,即子类可以对父类进行扩展。

3、子类可以通过自己的方式实现父类中的方法

3)多态

一个对象具体多种状态,表现父类引用指向多个子类的实例。

三要素:1、继承或者接口2、重写3、父类指向子类实例对象(向上转型:父类引用指向子类对象)

多态的特点:

1、对象类型和引用类型之间是继承/接口的关系。

2、引用类型调用方法时最终调用哪个类中的方法,是在运行时才能确定(即编译看左边,运行看右边)

3、不能调用子类中存在但父类中不存在的方法。

4、如果子类重写了父类中的方法,则真正执行的是子类覆盖的方法。如果没有重写,则执行的是父类中的方法。

7、接口和抽象类有什么共同点和区别?

共同点:

1、都不能实例化

2、都可以包含抽象方法

3、都可以由默认方法(JDK8特性之后)

4、都可以实现多态,一个变量引用多个不同类型的对象

5、都会对子类或实现类做出约束,必须提供特定的方法(重写抽象方法)

区别:

1、成员区别:抽象类有变量,常量,抽象方法,具体方法,构造方法。但是接口只有常量和抽象方法(1、抽象类中可以有成员变量,可以有多种访问修饰符。2、抽象类有构造方法)

2、关系区别:类只能继承一个类,但是可以实现多个接口

3、设计理念区别:接口主要是行为的实现,实现了哪个接口,就具有了相应的行为,而抽象类更多的是作为基类,强调的是所属关系。

8、深拷贝和浅拷贝区别了解吗?什么是引用拷贝?

浅拷贝会在堆上创建一个对象(区别引用拷贝的一点),如果拷贝的原对象的属性内部是引用类型,此时会直接赋值内部对象的引用地址,那么则公用同一个内部对象。

深拷贝会拷贝整个对象,包括其内部的对象。

引用拷贝则是两个不同的引用指向同一个对象。

示意图

六、Object

1、 Object 类的常见方法有哪些?

getclass

hashcode()

clone()

equals()

toString()

notify()

notifyAll()

wait()

finalize

2、== 和 equals() 的区别

==在基本类型和引用类型中的作用不同

在基本类型中,表示判断值是否相等,而在引用类型中表示对象的内存地址是否相同,其实本质都是值的判断,只是引用类型是存储内存地址的,因此对内存地址进行比较。

equals()不能用于基本数据类型,使用两个对象的比较

如果方法没有进行重写,此时默认使用Object()的equals()方法,此时对两个对象的内存地址是否相等进行比较

如果方法进行了重写,例如String中的equals(),此时比较的是两个对象存储的值。

3、hashCode() 有什么用?

hashcode的作用是获得哈希值,目的是方便获取对象在哈希表中的索引位置。

注:Object是所有类的直接或间接父类,所以在所有子类中hashcode()都存在。

4、为什么要有 hashCode?

个人看法是与equals()相配合,降低查找成本,提高效率,因为如果没有hashcode需要去一个一个equals,但是如果有hashcode,会计算对象的hashcode,如果hashcode不同,则直接认定对象不同,如果相同,则使用equals()。这样就减少了使用equals()的次数,提高执行效率。

使用hashcode能够大大减少查找成本。

但是不能只用hashcode,因为hashcode相同不代表对象相同。

这是因为哈希冲突,hashcode相同,但是对象可能不同,此时发生哈希碰撞或哈希冲突。

总结:1、hashcode相同的对象,两者不一定相等。

2、hashcode相同,并且eqals()。那么两个对象相同

3、如果hashcode。

5、为什么重写 equals() 时必须重写 hashCode() 方法

因为两个对象相等,此时hashcode相等,如果重写了equals()但是没有重写hashcode,可能会造成equals()相同,但是hashcode不同,这就不符合规则了。

重写 equals() 时没有重写 hashCode() 方法的话,使用 HashMap 可能会出现什么问题。

1、不符合相等的对象具有想的hashcode这个原则。

2、如果两个相等的对象hashcode不同,那么当你使用这些对象作为键的时候,可能无法找到合适的对应的值,哈希表可能会出现未定义的行为。

七、Stirng

1、String、Stringbuffer和Stringbuilder的区别

1)可变性

String是不可变的,Stringbuffer和Stringbuilder是继承AbstractStringBuilder类,在这之中也是使用字符数组存储字符串的,但是他没有使用final和Static方法,并且提供了可以修改字符数组的一些方法,例如append。

2)线程安全性

String是不可变的,可以认为是常量,因此是线程安全的,StringBuilder和Stirngbuffer都是继承了AbstractStringBuilder,公用了许多的方法,但是StingBuffer对方法和调用的方法添加了同步锁,因此是线程安全的,但是StringBuilder没有添加同步锁,因此不是线程安全的。

3)性能

String每次修改的时候,都会重新创建一个String对象,然后指向新的对象,因此性能的低于StringBuffer和StringBuilder的,StringBuilder性能是要高于StringBuffer的,大概10~15%,但是会有线程不安全的情况。

2、为什么String是不可变的

image-20231126132506081

分析:这里String是final修饰的,因此String是最终类,不可以被继承,因此无法有继承子类进行修改。同时这里char value【】字符数组使用private和final修饰,并且没有提供外部操作的方法,因此是不可变的,其中private规定了权限是私有的,final则表示这个数组引用是不能改变的(但是其中的值可以,因此不是最根本的原因)

总结原因:

1、String类是final修饰的,是最终类,因此无法被继承,不存在子类修改的情况

2、字符数组被private和final修饰,并且没有对外提供操作数据的方法。

3、字符串拼接用“+” 还是 StringBuilder?

java中的+和+=号是经过特俗重载过的,而字符串拼接,则是先创建一个StringBuffer,通过调用他的append方法来达到拼接的效果,最后tostring()方法会返回一个对象,因此他会额外的创建对象,而且如果在循环中拼接字符串,会出现创建多个Stringbuilder,无法复用,性能比较低。而如果使用StringBuilder则不会出现这个问题。因此建议使用StringBuilder,但是在JDK9之后,使用了动态方法makeconcatwithconstants(),就可以使用“+”拼接了

4、String#equals() 和 Object#equals() 有何区别?

前一个是值的比较(因为重写了Object的方法),而后一个是内存地址的比较。

5、字符串常量池的作用了解吗?

是jvm为了减少性能消耗和内存空间专门为String开辟的一块存储区域,可以避免字符串的重复创建。

6、String s1 = new String("abc");这句话创建了几个字符串对象?

一个或者是两个。

1、如果字符串常量池没有对应字符串的引用,此时会创建两个字符串对象。

首先在字符串常量池中创建一个字符串对象,然后如果此时没有对应字符串的引用,此时会在java堆内存中创建字符串,然后保留字符串的引用。因此创建了两个字符串对象。

2、如果字符串常量池中有对应字符串的引用,此时只创建一个字符串对象。

这时会在java堆中强制新的创建一个字符串对象,此时s1等于它的引用,但是他与常量池中的不同,因为内存地址不相同。

7、String#intern 方法有什么作用?

Stirng.intern的作用:将指定字符串的引用保存在字符串常量池中。

1、如果字符串常量池中已经有对应字符串的引用,此时之间返回此引用。

2、如果字符串常量池中没有对应的引用,此时保存这个引用。并返回。

8、String 类型的变量和常量做“+”运算时发生了什么?

1)先说常量,jvm会将常量(编译期间可以确定的值)直接存放在字符串常量池中,而字符串的拼接也是在常量池中进行的,直接保存在常量池中。其中还有常量折叠,这意味这,常量表达式算出的结果直接镶嵌在代码中。

这里所说的编译期间可以确定的值,也就是常量,主要是:

1、基本数据类型常量和字符串常量

2、final修饰的字符串变量和基本数据类型变量

3、字符串+拼接后的字符串,基本数据类型算数运算和位运算后的数据

2)对于对象引用,+拼接时候使用Stringbuilder进行拼接的,此时返回的是对象,编译器无法在编译期间确定他的值。

但是如果使用了final修饰,这可以当作常量,此时编译器可以确定他的值,并且此时会使用常量折叠。因此可以直接确定。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值