CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

Java基础篇常见问题解答-源码交易平台丞旭猿

1 解释下什么是面向对象?面向对象和面向过程的区别?

面向对象:将事物封装成 具有属性和方法的 封装体;实现业务时的某种功能时直接调用对象/封装体对应的方法即可;

面向过程:以实现某种功能的函数为主,是将业务分割成 一些函数和数据 ,按照一定的流程执行这些函数,来实现业务。

性能上:面向过程更胜一筹,不需要进行类的实例化等操作;

开发维护上:面向对象更胜一筹,由于其 封装,继承,多态三大特性;更易于扩展,开发和维护,降低系统的耦合性;

2 面向对象的三大特性?分别解释下?

封装:将属性和方法封装对象中,向外提供访问接口,便于使用

继承:子类继承父类的属性和方法,对于父类私有的方法子类拥有不能使用;

多态:同一个接口/父类 ,使用不同实例执行 实现/子类 重写 的不同方法;多态的三大必要条件 重写;实现/继承;父类引用指向子类对象

3 详细讲讲对多态的认识

(以下父类即含有接口)

概念:同一个接口/父类 ,使用不同实例执行 实现/子类 重写 的不同方法;多态的三大必要条件 重写;实现/继承;父类引用指向子类对象

成员变量访问:

编译看左(左边的父类或者接口是否有这个)无则不通过

运行也看左(子类有没有没关系,都调用父亲)

成员方法访问:

编译看左(左边的父类或者接口是否有这个方法)无则不通过

运行看右(右边的类或者接口是否有这个方法)优则调用,无则找父类

使用多态创建的对象,子类调用的方法父类必须都有;

优点:

1.同一个父类或者接口下(同一套规范下),实现不同的业务只要 实现子类不同的对象即可;无需修改代码;低耦合性;便于扩展维护

2.定义方法时使用父类或者接口作为 方法参数,该方法可以接受一切子类对象,灵活性

缺点:

不能使用子类独有的功能;解决方法:强制类型转化

4 JDK、JRE、JVM 三者关系

JVM:

java虚拟机 内存中的虚拟计算机,主要功能是实现跨平台性

如何实现跨平台性?

JVM 中java指令为字节码指令,JVM的主要功能就是 将字节码指令 转化成 对应平台的机器码指令的;

JVM组件

  • 类加载器:将类文件.class加载到内存中。
  • 字节码验证工具:检查代码中是否存在访问限制违规。
  • 执行引擎:将字节码转换为可执行的机器码。
  • JIT:Just-In-Time,即时编译,用于提高 JVM 的性能,加快 Java 程序的执行速度。

JRE:

java Runtime Envirment java运行时环境,既然说到运行时了,java程序的运行 单单靠JVM是不行的,JVM对于字节码指令的解析还需要 JRE中的核心类库;

一般来说 JRE = JVM + 核心类库

JDK

Java Development Kit java开发工具包,包含了java语言的编译工具javac;基础类库(IO,线程,集合等等);JRE;以及其它的一系列用于开发、诊断、分析、调试、管理的工具和命令,如jarjavahnative2asciijdbjconsolejstatjpsjmapjhat等。

5. 重载和重写的区别

重载:同一类 内相同名字的方法,参数不同,与返回之无关(可以相同也可以不同)(但仅返回值不同,编译报错)

重写:子类重写父类或者接口 方法;除了方法体不同其他基本相同

细节:

重写方法中:子方法可见性应更大;返回类型 应更小(父类的返回类型或者其子类型)

6. Java 中是否可以重写一个 private 或者 static 方法?

都不可以

对于private :子类可以拥有父类所有成员,但无法使用私有成员包括方法 。即被private修饰的成员变量与方法只能类内访问使用(子类没办法访问和使用,所以更不可以被重写)

对于静态方法有两大特点:

  • 静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。 类方法(也就是静态方法)中不能直接调用类的非静态变量
  • 可以继承但不能被覆盖重写

7. 构造方法有哪些特性

方法名与类名一致

创建实例时自动调用

8.在 Java 中定义一个不做事且没有参数的构造方法有什么作用?

便于子类使用父类成员变量及方法

Java程序执行子类的构造器前,第一行会利用super调用父类的构造器,如果父类没有对应的构造方法会出现编译错误;因此父类中会有一个默认的空参构造器;

那么为什么要在子类的构造方法中使用super呢?

super表示当前类的父类,super()调用的是父类默认的构造方法,即这样可以对父类进行初始化。如何没有对父类进行初始化,当子类调用父类的方法时,便会从逻辑上出现错误,因为没对父类初始化,父类的方法和属性便没有内存空间。

9. JAVA创建对象方式

  1. new ;

2. 反射 使用 Class 类的 newInstance 方法,该方法调用无参的构造器创建对象(反射):Class.forName.newInstance();

3. 反序列化 比如调用 ObjectInputStream 类的 readObject() 方法;

4. clone;

10. 抽象类和接口

从设计层面上看,抽象类提供了一种 IS-A 关系,需要满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。

继承方面

  • 一个类可以实现多个接口,但是不能继承多个抽象类。

方法方面

  • 抽象类可以有构造方法,接口中不能有构造方法; 抽象类有构造方法,但是不是用来实例化的,是用来初始化的
  • 一个抽象类中的方法不一定是抽象方法,即其中的方法可以有实现(有方法体),java8 前接口中的方法都是抽象方法,不能有方法体,只有声明;8时 有默认方法和静态 可以有方法体
  • j8接口中的方法只能是public、static、default(J9 有private),而抽象类的成员可以有多种访问权限。

成员变量方面

  • 抽象类可以有普通成员变量而接口不可以.
  • 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。

11. 静态变量和成员变量

静态变量:static修饰,类变量,不管创建多少对象,静态变量在内存中仅存在一份,属于共享变量

成员变量:属于某一实例,访问时,需要创建对象,通过调用对象中的该变量来访问

12. short s1 = 1;s1 = s1 + 1;有什么错?那么 short s1 = 1; s1 += 1;呢?有没有错误?

对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。

而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 =(short)(s1 + 1);其中有隐含的强制类型转换

证明:

public class Test {
    public static void main(String[] args) {
        short a = 1;
        a += 1;
    }
}
字节码伪指令
      stack=2, locals=2, args_size=1
         0: iconst_1
         1: istore_1
         2: iload_1
         3: iconst_1
         4: iadd
         5: i2s   //强转 s1 = (short)(s1 + 1)
         6: istore_1
         7: return

13.Integer 和 int 的区别?

Integer :包装类型,作为成员变量时,默认值为null,局部变量时使用时需要初始化;;

int:基本类型,作为成员变量时默认值为0;局部变量时使用时需要初始化;

扩展:

1.两者转化支持自动拆装箱;

2.包装类型之间 比较(==)时,包装类型 比较的是地址值,比较数值用equals();

3.Integer 非new方式创建时,[-128,127]范围内时,直接从常量池中取缓存值;

Java 在编译 Integer i = 100 时,会编译成 Integer i = Integer.valueOf(100),而 Integer 类型的 valueOf 的源码如下所示:

public static Integer valueOf(int var0) 
{ return var0 >= -128 && var0 <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[var0 + 128] : new Integer(var0);}

从上面的代码中可以看出:Java 对于 [-128, 127] 之间的数会进行缓存,比如:Integer i = 127,会将 127 进行缓存,下次再写 Integer j = 127 的时候,就会直接从缓存中取出,而对于这个区间之外的数就需要 new 了。

14. 拆箱和装箱的关系

自动装箱是 Java 编译器在基本数据类型和对应得包装类之间做的一个转化。比如:把 int 转化成 Integer,double 转化成 Double 等等。反之就是自动拆箱。

15. switch(?) ? 可以是哪些类型

Java5以前,只能是 整数表达式 int或者Integer 或枚举常量 ;同时byte,short,char可以转化成int类型,也算入其中;

JDK1.6:引入enum

JDK1.7时:又增加了String

16. final、finally、finalize

final 用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖、被其修饰的类不可继承;

finlly: try catch 执行的最后必须执行的代码块

finalize 用于对象回首时执行的函数

17. 讲讲final修饰符

1. 修饰数据

声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。

  • 对于基本类型,final 使数值不变;在赋值之后无法改变。
  • 对于引用类型,final 使引用不变,也就不能引用其它对象,在赋值后其指向地址无法改变,但是对象内容属性 还是可以改变的

2. 修饰方法

声明方法不能被子类重写。可以被本类重载

  1. private 方法隐式地被指定为 final
  2. 如果在子类中定义的方法和基类中的一个 private 方法签名相同此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。

3. 修饰类

  1. 声明类不允许被继承,不能有子类;
  2. 对于类和方法来说,abstract关键字和final关键字不能同时使用不能修饰抽象类,因为抽象类一般都是需要被继承的,final修饰后就不能继承了。

4. 赋值方式

final修饰的成员变量在赋值时可以有三种方式。

1、在声明时直接赋值。

2、在构造器中赋值。

3、在初始代码块中进行赋值。

final int x = 1;
// x = 2;  // cannot assign value to final variable x
final A y = new A();
y.a = 1;

注意:由于成员变量有默认值(0;null),因此final修饰成员变量时必须赋值;

  • 直接赋值
  • 所有的构造方法都对这个成员变量进行赋值

18. == 和 equals 的区别?

= =:如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等。

equals:比较对象内容 ,具体比较内容 需要根据重写的equals方法体

如果没有对 equals 方法进行重写,则比较的是引用类型的变量所指向的对象的地址(很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等)。

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

不一定;

在散列表中,hashCode相同的键值会出现哈希冲突,哈希冲突时键值不同但hashCode相同;

20. 为什么重写 equals() 就一定要重写 hashCode() 方法?

为了保证不违背hashCode方法中相同对象(equals()返回true)必须有相同哈希值的约定。

hashCode方法的重写原则就是保证equals方法认定为相同的两个对象拥有相同的哈希值

重写是为了维护hashCode方法设计的定义,但是为什么要维护hashCode方法设计的定义呢

实际上 需要用到 HashMap、HashSet 等 Java 集合,用不到哈希表的话,其实仅仅重写 equals() 方法也可以;

由于原始hashCode计算方法是 根据地址值映射出的哈希值,在散列表中通过这些哈希值来判断存储位置;

而原始的equals方法则是直接比较地址值,此时equals和hashcode方法显然是遵守约定的;

但如果只重写了equals方法,很可能导致保证equals方法认定为相同的两个对象拥有不同的哈希值,不同的哈希值对应的存储位置必然不同,这就会出现 散列表中 存在两个相等键值的情况;

21. & 和 && 的区别?

前者 两边均要计算

后者 前面出现 false 则不必计算后面

此外:& 还可以用作位运算符:当 & 两边的表达式不是 Boolean 类型的时候,& 表示按位操作。

22. Java 中的参数传递时传值呢?还是传引用?

尽管方法中传入引用类型时,方法内部可以改变引用类型的内容

但 实际上和值传递一样,仅仅是拷贝了地址值付给形参;

方法内部是修改地址值指向的内容;没有改变实参 指向地址

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

round 表示四舍五入,算法为Math.floor(x+0.5) ,即将原来的数字加上 0.5 后再向下取整,所以 Math.round(1.5) 的结果为 2,Math.round(-1.5) 的结果为 -1。

24. 如何实现对象的克隆?

(1) clone 重写 Object 类中的 clone() 方法 ;

直接重写的话以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。

应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

(2) 序列化 反序列化 序列化就是将一个对象转换成字节序列,方便存储和传输。

25. 深克隆和浅克隆的区别?

浅克隆:拷贝对象和原始对象的引用类型引用同一个对象。浅克隆只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅克隆。

深克隆:拷贝对象和原始对象的引用类型引用不同对象。深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝

深克隆的实现就是在引用类型所在的类实现 Cloneable 接口,并使用 public 访问修饰符重写 clone 方法。

Java 中定义的 clone 没有深浅之分,都是统一的调用 Object 的 clone 方法。为什么会有深克隆的概念?是由于我们在实现的过程中刻意的嵌套了 clone 方法的调用。也就是说深克隆就是在需要克隆的对象类型的类中重新实现克隆方法 clone()。

26. Java序列化,如何实现序列化

对象序列化是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或通过网络发送到任何其他程序。

从字节流创建对象的相反的过程称为反序列化。而创建的字节流是与平台无关的,在一个平台上序列化的对象可以在不同的平台上反序列化。序列化是为了解决在对象流进行读写操作时所引发的问题。

序列化的实现:将需要被序列化的类实现 Serializable 接口,该接口没有需要实现的方法,只是用于标注该对象是可被序列化的

然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream 对象,接着使用 ObjectOutputStream 对象的 writeObject(Object obj) 方法可以将参数为 obj 的对象写出,要恢复的话则使用输入流。

27. 序列化使用场景

(1)对象存储:当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;

(2)网络对象传输:当你想用套接字在网络上传送对象的时候;

(3)当你想通过 RMI 传输对象的时候。

28. 什么是泛型中的限定通配符和非限定通配符 ?

限定通配符:

符号形象解释:T2

文字解释:

:?需要是 T1的子类

:?需要是T2的父类;

非限定通配符:

29 反射的作用

反射是框架设计的灵魂

框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

什么是反射:

  • 通过类的字节码文件获取类中的成员并使用
  • 将类的各个组成部分(成员变量、构造方法、方法)封装为其他对象,这就是反射机制

反射的作用

反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。

  • 分析类
    • 加载并初始化一个类
    • 查看类的所有属性和方法
  • 查看并使用对象
    • 查看一个对象的所有属性和方法
    • 使用对象的任意属性和方法

30. Java 中的动态代理是什么?有哪些应用?

31. static 关键字的作用

修饰的属性:不需要实例化可以直接通过类名. 的方式调用; 在内存中静态变量(类变量)仅存在一份,全局共享;

修饰的方法:不需要实例化可以直接通过类名. 的方式调用;

静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字;

修饰代码块:类初始化时会运行一次

修饰内部类:非静态内部类依赖于外部类的实例,而静态内部类不需要。同时静态内部类不能访问外部类的非静态的变量和方法;

32. super 关键字的作用?

  • 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。应该注意到,子类一定会调用父类的构造函数来完成初始化工作,一般是调用父类的默认构造函数,如果子类需要调用父类其它构造函数,那么就可以使用 super() 函数。
  • 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。

33. transient 关键字的作用

对于不想进行序列化的变量,使用 transient 关键字修饰。

transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化。当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方法。

34. 字节和字符的区别

一个字节有8位;表示内存存储单位;

字符属于数字,字母等各种符号,不同的字符占有不同的字节数;

35. String 为什么设计成不可变类

(1)字符串的频繁使用,反复创建对象开销较大;因此引入串池机制;字符串池存储着 创建过的字符串;创建字符串时如果串池中有直接引用即可;因此 基于串池的需要设计成不可变类

(2)String 被许多的 Java 类(库)用来当做参数,例如:网络连接地址 URL、文件路径 path、还有反射机制所需要的 String 参数等, 假若 String 不是固定不变的,将会引起各种安全隐患

36. String、StringBuilder、StringBuffer 的区别?

String:不可变类;

StringBuilder: 引入字符串缓冲机制;但线程不安全;

StringBuffer: 同引入字符串缓冲机制;但线程安全, 内部方法使用synchronized 进行同步

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象

//使用锁机制
  public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

37. String 字符串修改实现的原理?

String 修改有很多情况:

  1. 字符变量拼接 :调用StringBuilder.append()方法实现字符拼接;最后调用 toString() 方法把结果返回。
  2. 字符常量拼接:编译期优化,编译期就直接存在串池中,直接从串池中取;
  3. 字符引用变化:直接改变引用值;

38. String str = i 与 String str = new String(i) 一样吗?

不一样,

前者结果存储在 串池中(串池在方法区);后者结果存储在堆内存中

在执行 String str1 = abc 的时候,JVM 会首先检查字符串常量池中是否已经存在该字符串对象,如果已经存在,那么就不会再创建了,直接返回该字符串在字符串常量池中的内存地址;如果该字符串还不存在字符串常量池中,那么就会在字符串常量池中创建该字符串对象,然后再返回。所以在执行 String str2 = abc 的时候,因为字符串常量池中已经存在abc字符串对象了,就不会在字符串常量池中再次创建了,所以栈内存中 str1 和 str2 的内存地址都是指向 abc 在字符串常量池中的位置,所以 str1 = str2 的运行结果为 true。

在执行 String str3 = new String(abc) 的时候,JVM 会首先检查字符串常量池中是否已经存在abc字符串,如果已经存在,则不会在字符串常量池中再创建了;如果不存在,则就会在字符串常量池中创建 abc 字符串对象,然后再到堆内存中再创建一份字符串对象,把字符串常量池中的 abc 字符串内容拷贝到内存中的字符串对象中,然后返回堆内存中该字符串的内存地址,即栈内存中存储的地址是堆内存中对象的内存地址。String str4 = new String(abc) 是在堆内存中又创建了一个对象,所以 str 3 str4 运行的结果是 false。

39. final 修饰 StringBuffer 后还可以 append 吗?

final修饰变量,只是限定了引用唯一不可变更;对内容不做要求

40. Java 中的 IO 流的分类?说出几个你熟悉的实现类?

字节流:FileInputStream FileOutStream

字符流:FileReader FileWriter

41. 字节流和字符流有什么区别?

  • 字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元 两个字节。
  • 字节流默认不使用缓冲区;字符流使用缓冲区。
  • 字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。

41. package包的用途

防止命名冲突,不同包类名可以一样;

模块化管理,一种功能封装到同一个包中;

代码复用;

声明:本文部分素材转载自互联网,如有侵权立即删除 。

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容