Java基础总结(2)

1.实例方法和静态方法的区别

  • 调用方式不同:静态方法可以通过类名.方法名直接调用,也可以通过当前类的实例对象.方法名来调用,但是实例方法只能通过后者来访问
  • 访问类的成员存在限制:在静态方法内部,只能访问类的静态成员,不允许访问非静态成员;而实例方法不受限制

2.值传递和引用传递的区别

  • 值传递是指在方法调用时,将实际参数的值复制一份传递给形式参数,相当于将副本传递了过去。对形式参数的修改不会影响实际参数的值。
  • 引用传递是指在方法调用时,将实际参数的引用(内存地址)传递给形式参数。形式参数和实际参数指向同一块内存地址,对形式参数的修改会影响实际参数的值。
    注意区分实际参数和形式参数

3.重载和重写的区别

  • 重载:发生在同一个类中,方法名相同,但是方法的形参顺序、个数、数据类型、方法的返回值、方法的修饰符可以不同
  • 重写:发生在父子类中,方法名相同,形参列表相同;
    同时遵循“两同、两小、一大”:就是方法名相同、形参列表相同,子类重写的方法的返回值类型要小于父类方法、子类方法的声明抛出的异常必须小于或等于父类的,重写的方法的权限修饰符要大于或等于父类方法的
    注意:如果返回值是void或者基本数据类型,那么重写时不可以修改。如果是引用数据类型,那么可以返回引用数据类型的子类。

4.深拷贝和浅拷贝

前提: 深拷贝和浅拷贝的主要区别在于对于对象内部引用类型属性的处理方式。基本数据类型直接存储在栈中,引用数据类型在栈中存储引用,真实的数据放在堆内存内。
1.浅拷贝(Shallow Copy):
浅拷贝指在克隆操作中,只复制对象本身以及对象内部的基本数据类型的属性,以及实例对象的引用地址,而不复制引用类型所指向的属性,新旧对象还是共享同一块内存。
为了实现浅拷贝,实现 Cloneable 接口和重写 clone() 方法;
2.深拷贝(Deep Copy):
深拷贝指在克隆操作中,除了复制对象本身以及对象内部的基本数据类型的属性外,还要递归地复制对象内部的引用类型的属性。即深度克隆了所有引用类型的属性。
为了实现深拷贝,需要将对象及其关联的对象都实现序列化,再反序列化为对象
面试题:深拷⻉和浅拷⻉
深拷⻉和浅拷⻉就是指对象的拷⻉,⼀个对象中存在两种类型的属性,⼀种是基本数据类型,⼀种是实 例对象的引⽤。

  1. 浅拷⻉是指,只会拷⻉基本数据类型的值,以及实例对象的引⽤地址,并不会复制⼀份引⽤地址所 指向的对象,也就是浅拷⻉出来的对象,内部的类属性(引用数据类型)指向的是同⼀个对象
  2. 深拷⻉是指,既会拷⻉基本数据类型的值,也会针对实例对象的引⽤地址所指向的对象进⾏复制, 深拷⻉出来的对象,内部的属性指向的不是同⼀个对象

5.Java的可变长参数

从java5开始,java开始支持不定长参数,就是在调用方法时,允许传入不定长的参数,并且可变参数自能作为参数的最后一个,在方法重载时会优先匹配固定参数的方法

6.谈谈你对面向对象的理解

面向对象以对象为中心,将问题看成一个对象组成,这些对象有自己的属性和行为(方法),通过这些属性和行为共同协调解决问题
面向过程以过程为中心,强调的是解决问题的步骤、顺序,将解决问题分为若干个步骤,再分别依次执行
封装: 对与一个类内部的属性和成员,进行封转,对外隐藏内部的实现细节,只对外暴露必要的接口,调用不知道内部的实现细节
继承: 子类继承父类的属性和方法,可以进行自己的扩展,对于父类含有的方法和属性,不需要再重新定义
多态: 同一方法在不同的对象上产生的不同的行为。

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

  1. 定义位置不同:成员变量定义在类中、方法体外,又分为实例变量和类变量(用static修饰的变量);局部变量定义在方法体中或局部代码块中
  2. 生命周期不同:成员变量随着对象的创建而产生,随着对象销毁而消失;局部变量随着方法的压栈而产生,随着方法的弹栈而消失。
  3. 存储位置不同:实例变量存储在堆内存中,与对象一起分配空间,类变量存储在方法区中,局部变量存储在栈内存中(成员变量存储在堆中,局部变量存储在栈中)
  4. 作用域不同:成员变量作用于整个类,而局部变量只作用于它所在的方法、代码块、构造方法中
  5. 初始化不同:成员变量有默认值,而局部变量在使用时,必须进行显试初始化
  6. 修饰符的使用不同:成员变量可以被public,protect,private,static等修饰符修饰,而局部变量不能被控制修饰符及static修饰;两者都可以定义成final型。

8.对象实体和对象引用的区别

对象实体: 指的是在内存中真正存在的对象,它占据一定的内存空间,并保存了对象的属性值。
对象引用: 指的是对对象的引用或者说指针,它是一个变量,用于存储对象在内存中的地址。通过对象引用,我们可以访问和操作对象的属性和方法。
简单来说,对象实体是具体的对象,而对象引用是指向对象实体的指针(jjava中没有指针,这里是比喻的说法)。

9.构造方法的作用,特点

  • 构造方法是用于创建和初始化对象的特殊方法。
  • 构造方法与类同名,没有返回类型。
  • 构造方法可以重载,但不能被继承或覆盖。
  • 默认构造方法是编译器自动生成的,如果没有显式定义任何构造方法,默认会有无参数的构造方法。但是如果定义了有参构造方法,那么默认的构造方法就消失了。
  • 构造方法不能手动调用,在创建类实例的时候自动调用构造方法。

10.反射

什么是反射
Java的反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法 ;对于任意一个对象,都能够调用它的任意一个方法和属性 ;这种 动态获取的信息以及动态调用对象的方法的功能 称为 Java 语言的反射机制。
简单说就是:能够通过类的名字获取到类的关键信息

如下图:在这里插入图片描述
反射调用方法
优缺点(仅供参考)

优点:使用者可以在运行时动态获取类的各种信息,使得代码更加灵活;
通用性: 反射提供了一种通用的访问类信息和操作类对象的手段,这使得一些通用的库、框架和工具能够在不知道具体类的情况下进行操作,增加了代码的通用性和可重用性。
适用于编写通用代码: 通过反射,可以编写一些通用的代码,例如序列化、反序列化、对象映射等,而不需要针对每个类编写特定的代码。
缺点:反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;安全问题,反射允许访问类的私有信息,可能破坏封装性;代码可读性降低
使用场景(仅供参考)

  1. 框架和工具
    许多框架和工具使用反射来实现插件化架构,允许在运行时动态加载和执行类,从而实现更灵活的扩展和定制。
  2. 配置文件解析
    反射可以用于解析配置文件,实例化成java对象,使得配置更加灵活且易于维护(可读性)。
  3. junit单元测试
    在单元测试中,反射可以被用来调用私有方法、设置私有字段等,以便更好地进行测试,并确保代码的健壮性和可维护性。
  4. 注解处理器
    某些框架和库使用反射来处理注解,例如Spring框架通过反射实现了依赖注入的功能。
  5. ORM(对象关系映射)
    ORM框架通常使用反射来映射Java对象与数据库表之间的关系,实现数据的持久化和检索。比如说Hibernate

获取Class的几种方式
Class.forName(“全类名”);
类名.class
对象.getClass()
通过类加载器获取
如下:

public class Demo {
   public static void main(String[] args) throws ClassNotFoundException {
       //1.Class.forName(“全类名”);
       Class<?> demoClass1 = Class.forName("List.Demo");
   	   //2.类名.class
       Class<Demo> demoClass2 = Demo.class;
       //3.对象.getClass()
       Demo demo = new Demo();
       Class<? extends Demo> demoClass3 = demo.getClass();
       //4.通过类加载器获取
       ClassLoader classLoader = Demo.class.getClassLoader();
       Class<?> demoClass4 = classLoader.loadClass("List.Demo");
       System.out.println(demoClass1);
       System.out.println(demoClass2);
       System.out.println(demoClass3);
       System.out.println(demoClass4);
}

输出:

class List.Demo
class List.Demo
class List.Demo
class List.Demo

11.序列化和反序列化

序列化:把对象转换为字节序列的过程称为对象的序列化.
反序列化:把字节序列恢复为对象的过程称为对象的反序列化
作用:对内存中的对象进行持久化或网络传输,这个时候都需要序列化和反序列化.
避免被序列化的方法
使用Transient关键字:Java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。
也就是说被transient修饰的成员变量,在序列化的时候其值会被忽略,在被反序列化后, transient 变量的值被设为初始值, 如 int 型的是 0,对象型的是 null。
为什么要显示指定 serialVersionUID 的值?谈谈你的理解?
在进行序列化对象时,序列化版本号会随对象的属性一起进行序列化(其实版本号没有被序列化,JVM 在序列化对象时会自动生成一个 serialVersionUID,然后将显示指定的 serialVersionUID 属性值赋给自动生成的 serialVersionUID),然后进行网络传输或持久化,在进行反序列化时,jvm会读取序列化流中的serialVersionUID,然后将这个版本号和之前的版本号进行比对,如果相同那么就序列化成功,否则失败。
如果显示指定了 serialVersionUID,JVM 在序列化和反序列化时就会保证serialVersionUID相等,值为显示指定的值,这样在反序列化时新旧版本的 serialVersionUID 就一致了.
如果不指定版本号,那么会造成版本号不一致的的问题,但是如果类写完后不再修改,那么不指定serialVersionUID,也是不会有问题的,但是不修改类几乎是不可能的,所以一般指定版本号

12.键盘输入的实现方式

1.通过System.in.read()输入,返回一个int类型数据
2.通过Scanner类扫描输入
3.通过输入流输入通过InputStreamReaderBufferedReader输入,
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = br.readLine();
sc.next()和sc.nextLine()有什么区别?
next()遇到空格停止接收。

13.字节流和字符流的区别

区别参考
1.基本单位不同:字节流以字节为单位、字符流以字符为单位
2.处理的数据不同:字节流可以处理任何类型的数据,比如视频,图片文本,字符流只能处理文本数据
3.性能不同:字符流通常提供了缓冲机制,可以减少对底层操作系统的调用次数,从而提高性能。当使用字符流进行读写操作时,数据会先被写入到缓冲区中,当缓冲区满或者调用flush方法时,才会将数据真正写入到文件或者从文件中读取数据。
如果需要处理不同字符编码的文本文件,字符流需要进行字符编码的转换,这可能会影响性能。而字节流不受字符编码的影响,可以直接处理原始的字节数据。
所以当频繁地操作数据时,可以用字符流,不频繁时两者的效率相当

14.java中的异常体系

Java中所有异常都来自顶级父类Throwable。
Throwable下有两个字类ExceptionError
Error是程序无法处理的错误,一旦出现这个错误,则程序将被迫停止运行。
Exception不会导致程序停止,又分为两个部分UnCheckedExceptionCheckedException检查异常。UnCheckException下面有RunTimeException和其子类。
RunTimeException常常发生在程序运行过程中,会导致程序当前线程执行失败。CheckedException常常发生在程序编译过程中,会导致编译不通过。

15.switch语句可以作用于哪些数据类型

  1. byte,short,int,char,枚举,在java7(jdk1.7)之后也支持String类型
  2. 不支持float,double,long和boolean

16.java的保留字

参考答案:Java保留字:现有Java版本尚未使用,但以后的版本可能会作为关键字使用。命名标识符时要避免使用这些保留字
gotoconst

17.四种访问权限修饰符?

  • 封装的四种权限修饰符以及访问范围?
  • private
    • 访问范围:仅在定义它的类内部可见。
    • 用途:用于隐藏类的内部实现细节,确保类的属性和方法不被外部直接访问。
  • default(没有修饰符):
    • 访问范围:在同一个包内可见,不使用任何修饰符时默认为包访问级别。
    • 用途:用于在同一个包内的其他类之间共享类、方法和属性,但不允许其他包访问。
  • protected
    • 访问范围:在同一个包内的类以及不同包中继承该类的子类中可见。
    • 用途:用于允许子类访问父类的成员,同时也可以被同一个包内的其他类访问。
  • public
    • 访问范围:对所有类可见,没有访问限制。
    • 用途:用于定义类、方法、构造函数和属性,以便它们可以被任何其他类访问,无论它们位于哪个包中。

18.HashSet、LinkedHashSet、TreeSet的区别

相同点:

  • HashSet、LinkedHashSet、TreeSet都实现了Set接口
  • 三者都保证了元素的唯一性,即不允许元素重复
  • 三者都不是线程安全的
    要想实现线程安全,可以使用 Collections.synchronizedSet(Set<T> s)

不同点:

  • 存储结构:
    HashSet:基于哈希表实现,元素无序。
    LinkedHashSet:基于哈希表和链表实现,元素按照插入顺序排序。(保证FIFO(先进先出)即按插入顺序排序,内部维护了一个双向链表来记录插入顺序)
    TreeSet:基于红黑树实现,元素按照自然顺序或指定的比较器进行排序。
  • null值方面:
    HashSetLinkedHashSet允许添加null值,TreeSet不允许添加null值,添加null时会抛出java.lang.NullPointerException异常。
  • 性能:
    HashSet提供了最快的查找速度(平均时间复杂度为O(1)),基于hashCode()确定元素的位置,但在迭代时顺序是不确定的。
    LinkedHashSet在迭代时保持了插入顺序,查找速度略慢于HashSet(平均时间复杂度为O(1))(虽然哈希表的查找速度仍然很快(平均时间复杂度为O(1)),但由于需要维护链表来记录顺序,所以LinkedHashSet的插入和删除操作略慢于HashSet。)。
    TreeSet提供了最慢的查找速度(平均时间复杂度为O(log n)),但在迭代时可以按照顺序访问元素。

就这了…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值