JavaSE知识点(2)
目录
访问修饰符的区别
this关键字的作用
抽象类和接口有什么区别
抽象类可以定义构造方法吗
但是接口不可以定义构造方法
Java支持多继承吗
接口可以多继承吗
继承和抽象的区别?
抽象类和普通类的区别
成员变量和局部变量的区别?
staic关键字了解吗
final关键字的作用
final,finally,finalize区别
==和equals的区别
为什么重写equals时必须重写hashcode方法
什么是hashcode方法
为什么要有hashcode方法
为什么两个对象有相同的hashcode值,却不一定相等呢
Java是值传递还是引用传递
深拷贝和浅拷贝的区别
java创建对象的方式有哪几种
new子类的时候,父类和父类静态代码块,构造方法的执行顺序
String
String是Java的基本数据类型吗,可以被继承吗
String有哪些常用的方法
String,Stringbuffer,Stringbulider的区别
String
Stringbuilder
Stringbuffer
String str1 = new String("abc")和 String str2 =“abc”的区别
String是不可变类?字符串拼接是如何实现的?
如何保证String不可变
String如何转为Integer
访问修饰符的区别
ava 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。可以修饰在类、接口、变量、方法。
- private : 在同一类内可见。可以修饰变量、方法。注意:不能修饰类(外部类)
- public : 对所有类可见。可以修饰类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。可以修饰变量、方法。注意:不能修饰类(外部类)。
this关键字的作用
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。
1、普通的直接引用,this相当于是指向当前对象本身
2、形参与成员变量名字重用,用this区分
public Person(String name,int age){this.name=name;this.age=age;
}
3、引用本类的构造方法
抽象类和接口有什么区别
一个类只能继承一个抽象类,但一个类可以实现多个接口。所以我们在新建线程类一般推荐使用实现Runnable接口的方式,这样线程类还可以继承其他类,而不单单是Thread类。
抽象类符合is-a的关系,而接口更像是has-a的关系,比如说一个类可以序列化的时候,它只需要实现Seralizable接口就可以了,而不需要去继承一个序列化的类。
抽象类更多的是用来为多个相关的类提供一个共同的基础框架,包括状态的初始化,而接口则是定义了一套行为标准,让不同的类可以实现同一接口。提供行为的多样化实现。
抽象类可以定义构造方法吗
可以,抽象类可以有构造方法
但是接口不可以定义构造方法
接口主要用于定义一组方法规范,没有具体的实现细节
Java支持多继承吗
Java不支持多继承,一个类只能继承一个类,多继承会引发菱形继承问题
class A {void show() { System.out.println("A"); }
}class B extends A {void show() { System.out.println("B"); }
}class C extends A {void show() { System.out.println("C"); }
}// 如果 Java 支持多继承
class D extends B, C {// 调用 show() 方法时,D 应该调用 B 的 show() 还是 C 的 show()?
}
接口可以多继承吗
接口可以多继承,一个接口可以继承多个接口,使用逗号分隔
interface InterfaceA {void methodA();
}interface InterfaceB {void methodB();
}interface InterfaceC extends InterfaceA, InterfaceB {void methodC();
}class MyClass implements InterfaceC {public void methodA() {System.out.println("Method A");}public void methodB() {System.out.println("Method B");}public void methodC() {System.out.println("Method C");}public static void main(String[] args) {MyClass myClass = new MyClass();myClass.methodA();myClass.methodB();myClass.methodC();}
}
在上面的例子中,InterfaceA 和 InterfaceB 是两个独立的接口。
InterfaceC 继承了 InterfaceA 和 InterfaceB,并且定义了自己的方法 methodC。
MyClass 实现了 InterfaceC,因此需要实现 InterfaceA 和 InterfaceB 中的方法 methodA 和 methodB,以及 InterfaceC 中的方法 methodC。
继承和抽象的区别?
继承是一种允许子类继承父类属性和方法的机制。通过继承,子类可以重用父类的代码
抽象是一种隐藏复杂性和只显示必要部分的技术,在面向对象编程中,抽象可以通过抽象类和接口实现
抽象类和普通类的区别
抽象类使用abstract关键字定义,不能被实例化,只能最为其他类的父类。普通类没有 abstract 关键字,可以直接实例化。
抽象类可以包含抽象方法和非抽象方法。抽象方法没有方法体,必须由子类实现。普通类只能包含非抽象方法。
成员变量和局部变量的区别?
1、语法上来看:成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被public,private,static等修饰符修饰,局部变量不能被修饰符修饰。但是成员变量和局部变量都能被final修饰
2、从变量在内存的存储来看: 如果成员变量使用staic修饰的,那么这个成员变量是属于类的,如果没有staic修饰,那么是属于实例的。对象存于堆内存,如果局部变量类型为基本数据类型,那么存储在栈内存,如果为引用数据类型,那存放的是指向堆内存对象的引用或者是指向常量池中的地址。
3、从变量在内存的生存时间来看:成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。
4、成员变量如果没有被赋初值:则会自动以类型的默认值而赋值(被final修饰的成员变量也必须显示的赋值),而局部变量则不会自动赋值
staic关键字了解吗
static关键字可以用来修饰变量,方法,代码块和内部类,以及导入包
修饰对象 | 作用 |
---|---|
变量 | 静态变量,类级别变量,所有实例共享同一份数据。 |
方法 | 静态方法,类级别方法,与实例无关。 |
代码块 | 在类加载时初始化一些数据,只执行一次。 |
内部类 | 与外部类绑定但独立于外部类实例。 |
导入 | 可以直接访问静态成员,无需通过类名引用,简化代码书写,但会降低代码可读性。 |
静态变量: 是被 static 修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个副本。
实例变量: 必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。
静态方法:static 修饰的方法,也被称为类方法。在外部调⽤静态⽅法时,可以使⽤"类名.⽅法名"的⽅式,也可以使⽤"对象名.⽅法名"的⽅式。静态方法里不能访问类的非静态成员变量和方法。
实例⽅法:依存于类的实例,需要使用"对象名.⽅法名"的⽅式调用;可以访问类的所有成员变量和方法。
final关键字的作用
1、当final修饰一个类时,表明这个类不能被继承。
2、当final修饰一个方法时,表明这个方法不能被重写
3、当final修饰一个变量时,表明这个变量的值一旦被初始化就不能被修改
final,finally,finalize区别
final是一个修饰符,可以修饰类,方法和变量。可以修饰类、方法和变量。当 final 修饰一个类时,表明这个类不能被继承;当 final 修饰一个方法时,表明这个方法不能被重写;当 final 修饰一个变量时,表明这个变量是个常量,一旦赋值后,就不能再被修改了。
finally 是Java中异常处理的一部分,用来创建 try 块后面的 finally 块。无论 try 块中的代码是否抛出异常,finally 块中的代码总是会被执行。通常,finally 块被用来释放资源,如关闭文件、数据库连接等。
finallize是Object类的一个方法,用于垃圾回收器将对象从内存中清除出去之前做一些必要的清理工作。
==和equals的区别
1、==用于比较两个对象的引用,即他们是否指向同一个对象实例。对于基本数据类型,==比较的是值是否相等
2、equals用于比较两个对象的内容是否相等,但是默认情况下和==相同,比较对象引用。然而,equals()
方法通常被各种类重写。例如,String
类重写了 equals()
方法,以便它可以比较两个字符串的字符内容是否完全一样。
为什么重写equals时必须重写hashcode方法
因为基于哈希的集合类(如 HashMap)需要基于这一点来正确存储和查找对象。
具体地说,HashMap 通过对象的哈希码将其存储在不同的“桶”中,当查找对象时,它需要使用 key 的哈希码来确定对象在哪个桶中,然后再通过 equals()
方法找到对应的对象。
如果重写了 equals()
方法而没有重写 hashCode()
方法,那么被认为相等的对象可能会有不同的哈希码,从而导致无法在 HashMap 中正确处理这些对象。
什么是hashcode方法
hashCode()
方法的作⽤是获取哈希码,它会返回⼀个 int 整数,定义在 Object 类中, 是一个本地⽅法。
为什么要有hashcode方法
hashcode方法主要用于来获取对象的哈希码,哈希码是由对象的内存地址或者对象属性计算出来的,它是一个int类型的整数,通常是不会重复的,因此可以用来作为键值对的建,以提高查询效率。
为什么两个对象有相同的hashcode值,却不一定相等呢
哈希码是通过哈希函数将对象中映射成一个整数值,其主要目的是在哈希表中快速定位对象的存储位置。
由于哈希函数将一个较大的输入域映射到一个较小的输出域,不同的输入值(即不同的对象)可能会产生相同的输出值(即相同的哈希码)。
这种情况称为哈希冲突。当两个不相等的对象发生哈希冲突时,它们会有相同的 hashCode。为了解决哈希冲突的问题,哈希表在处理键时,不仅会比较键对象的哈希码,还会使用 equals 方法来检查键对象是否真正相等。如果两个对象的哈希码相同,但通过 equals 方法比较结果为 false,那么这两个对象就不被视为相等。
Java是值传递还是引用传递
Java是值传递
当一个对象被作为参数传递到方法中时,参数的值就是该对象的引用。引用的值是对象在堆中的地址。对象是存储在堆中的,所以传递对象的时,可以理解为把变量存储的对象地址给传递过去。
深拷贝和浅拷贝的区别
在 Java 中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两种拷贝对象的方式,它们在拷贝对象的方式上有很大不同。
浅拷贝会创建一个新的对象,但这个对象的属性和原对象的属性完全相同。如果属性是基本数据类型,拷贝的是基本数据类型的值;如果属性是引用类型,拷贝的是引用地址。因此新旧对象共享一个引用对象。
浅拷贝的实现方式:实现Cloneable接口并重写clone方法
深拷贝也会创建一个新对象,但是会递归的赋值所有的引用对象,确保新对象和原对象完全独立。新对象与原对象的任何更改都不会相互影响。
深拷贝的实现方法有:手动复制所有的引用对象,或者使用序列化和反序列化。
java创建对象的方式有哪几种
new子类的时候,父类和父类静态代码块,构造方法的执行顺序
1、首先执行父类的静态代码块(仅在第一次加载时执行)
2、接着执行子类的静态代码块(仅在类第一次加载时执行)
3、再执行父类的构造方法
4、最后执行子类的构造方法
String
String是Java的基本数据类型吗,可以被继承吗
不是,String是一个类,属于引用数据类型。String也不可以被继承,因为被final修饰
String有哪些常用的方法
1、length 返回字符串长度
2、charAt 返回指定位置的字符
3、substring 返回字符串的一个子串
4、contains 检查字符换是否包含指定的字符序列
5、equals比较两个字符串内容是否相等
6、indexof 返回指定字符或者字符串首次出现的位置
7、replace替换字符串中的字符或字符序列
8、trim去除字符串两端的空白字符
9、split 根据给定正则表达式的匹配拆分此字符串
String,Stringbuffer,Stringbulider的区别
String
、StringBuilder
和StringBuffer
在 Java 中都是用于处理字符串的,它们之间的区别是,String 是不可变的,平常开发用得最多,当遇到大量字符串连接时,就用 StringBuilder,它不会生成很多新的对象,StringBuffer 和 StringBuilder 类似,但每个方法上都加了 synchronized 关键字,所以是线程安全的。
String
String
类的对象是不可变的。也就是说,一旦一个String
对象被创建,它所包含的字符串内容是不可改变的。- 每次对
String
对象进行修改操作(如拼接、替换等)实际上都会生成一个新的String
对象,而不是修改原有对象。这可能会导致内存和性能开销,尤其是在大量字符串操作的情况下。
Stringbuilder
StringBuilder
提供了一系列的方法来进行字符串的增删改查操作,这些操作都是直接在原有字符串对象的底层数组上进行的,而不是生成新的 String 对象。StringBuilder
不是线程安全的。这意味着在没有外部同步的情况下,它不适用于多线程环境。- 相比于
String
,在进行频繁的字符串修改操作时,StringBuilder
能提供更好的性能。 Java 中的字符串连+
操作其实就是通过StringBuilder
实现的。
Stringbuffer
StringBuffer
和StringBuilder
类似,但StringBuffer
是线程安全的,方法前面都加了synchronized
关键字。
String str1 = new String("abc")和 String str2 =“abc”的区别
直接使用双引号为字符串变量赋值时,Java 首先会检查字符串常量池中是否已经存在相同内容的字符串。
如果存在,Java 就会让新的变量引用池中的那个字符串;如果不存在,它会创建一个新的字符串,放入池中,并让变量引用它。
使用 new String("abc")
的方式创建字符串时,实际分为两步:
- 第一步,先检查字符串字面量 "abc" 是否在字符串常量池中,如果没有则创建一个;如果已经存在,则引用它。
- 第二步,在堆中再创建一个新的字符串对象,并将其初始化为字符串常量池中 "abc" 的一个副本。
new String("abc")创建了几个对象
字符串常量池中如果之前已经有一个,则不再创建新的,直接引用;如果没有,则创建一个。
堆中肯定有一个,因为只要使用了 new 关键字,肯定会在堆中创建一个。
String是不可变类?字符串拼接是如何实现的?
String 是不可变的,这意味着一旦一个 String 对象被创建,其存储的文本内容就不能被改变。这是因为:
①、不可变性使得 String 对象在使用中更加安全。因为字符串经常用作参数传递给其他 Java 方法,例如网络连接、打开文件等。
如果 String 是可变的,这些方法调用的参数值就可能在不知不觉中被改变,从而导致网络连接被篡改、文件被莫名其妙地修改等问题。
②、不可变的对象因为状态不会改变,所以更容易进行缓存和重用。字符串常量池的出现正是基于这个原因。
当代码中出现相同的字符串字面量时,JVM 会确保所有的引用都指向常量池中的同一个对象,从而节约内存。
③、因为 String 的内容不会改变,所以它的哈希值也就固定不变。这使得 String 对象特别适合作为 HashMap 或 HashSet 等集合的键,因为计算哈希值只需要进行一次,提高了哈希表操作的效率。
因为 String 是不可变的,因此通过“+”操作符进行的字符串拼接,会生成新的字符串对象。Java 8 时,JDK 对“+”号的字符串拼接进行了优化,Java 会在编译期基于 StringBuilder 的 append 方法进行拼接,String.join()
等方式
如何保证String不可变
第一,String 类内部使用一个私有的字符数组来存储字符串数据。这个字符数组在创建字符串时被初始化,之后不允许被改变。
第二,String 类没有提供任何可以修改其内容的公共方法,像 concat 这些看似修改字符串的操作,实际上都是返回一个新创建的字符串对象,而原始字符串对象保持不变。
第三,String 类本身被声明为 final,这意味着它不能被继承。这防止了子类可能通过添加修改方法来改变字符串内容的可能性。
String如何转为Integer
String 转成 Integer,主要有两个方法:
- Integer.parseInt(String s)
- Integer.valueOf(String s)
不管哪一种,最终还是会调用 Integer 类内中的parseInt(String s, int radix)
方法。