问题大纲
- 一、Java概念原理
- 1、Java中为什么要写None Static Method(非静态方法/实例化方法)?
- 2、动态代理是基于什么原理?【第6讲】(运行时自省,获取类声明属性和方法)
- 3、Java为什么不能多继承?
- 4、谈谈接口和抽象类有什么区别?【第13讲】(*3)
- 5、什么是内部类,什么是匿名内部类?
- 6、重写和重载的区别。(*2)
- 7、Exception和Error有什么区别?【第2讲】:Throwable类;可预料VS不可恢复;可检查+不可检查
- 8、谈谈final、finally、 finalize有什么不同?【第3讲】(*2)
- 9、String、StringBuffer、StringBuilder有什么区别?【第5讲】(*3)不可变,中间对象;线程安全;非线程安全
- 10、int和Integer有什么区别?【第7讲】(*2):包,自动装箱拆箱、值缓存,较小数值范围
- 二、参考
一、Java概念原理
1、Java中为什么要写None Static Method(非静态方法/实例化方法)?
答:静态方法常驻内存,定义太多会占用大量资源,可能导致溢出,而非静态方法随着实例对象被回收后消失,同时代码不会共享,线程安全。
- 补充:
角度 | Static Method | Non Static Method |
---|---|---|
生命周期 | 与静态类成员一样,装载进内存会常驻,直至JVM关闭 | 实例化后才分配内存,必须通过类实例引用,当实例对象被JVM回收后,跟着消失 |
内存位置 | 静态方法与静态变量创建后使用同一块内存,连续 | 存在内存多个地方,离散 |
效率 | 高 | 低 |
线程安全 | 静态方法(变量)共享代码(数据)段,有并发问题 | 针对确定对象,没问题 |
追问1:Java 高级特性?
-
1)泛型:参数化类型,即把数据类型变成一个可变参数。
-
2)反射:通过 名称来得到对象(类、属性、方法) 的技术。
如:可通过类名-->生成类实例;方法名-->调用方法;属性名-->访问属性值。
-
3)注解:对Java代码打标签,说明作用。
如:读懂代码、格式检查、减少配置、减少重复。可以在编译期检测,也可以运行时反射。
2、动态代理是基于什么原理?【第6讲】(运行时自省,获取类声明属性和方法)
答:反射赋予程序在运行时自省(introspect)的能力,可以直接操作类或者对象,如获取类定义、属性和方法
,甚至可以运行时修改类定义。
动态代理是一种运行时动态构建代理、处理代理方法调用的机制。利用类似机制的场景有 RPC 调用、AOP。
实现方式方面,JDK 自身提供的利用了反射机制,其他的有更高性能的字节码操作机制,类似 ASM、cglib(基于 ASM)、Javassist 等。
3、Java为什么不能多继承?
答:多继承指一个类同时从多个父类那继承行为和特征。图中X方法继承哪个类的方法呢?容易导致事故。
追问1:如何实现多继承?
答:接口或内部类。
4、谈谈接口和抽象类有什么区别?【第13讲】(*3)
- 1)接口是行为的抽象,是抽象方法的集合,可以利用接口达到API定义和实现分离的目的。
- 2)抽象类是不能实例化的类,形式上和一般类没区别,主要是为了代码重用。Java标准库(如collection框架)中很多通用部分(方法实现或成员变量)就被抽取成为抽象类。
接口说明:
1. 不能实例化,不能包含任何非常量成员,任何field都隐含public static final;
2. 没有非静态方法实现,只能是抽象或静态方法。接口举例:java.util.List[Java标准库]
// 实现interface用implements关键词,继承abstract class用extends关键词。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//...
}
5、什么是内部类,什么是匿名内部类?
- 1)内部类:将一个类的定义,放在另一个类的定义内部。内部类继承自某个类或实现某个接口,操作外围类的对象。
- 2)匿名内部类:没有名字的内部类。只能使用一次(因为没名字),常用来简化代码编写,
- 3)匿名类使用前提:必须继承一个父类或实现一个接口。
6、重写和重载的区别。(*2)
1)含义
- 重写:子类对父类的方法进行重新实现。即外壳不变,核心重写。
- 重载:每个重载方法(或构造函数)都必须有独一无二的参数类型列表。
2)比较
区别点 | 重写 | 重载 |
---|---|---|
参数列表 | 一定不能修改 | 必须修改 |
返回类型 | 一定不能修改 | 可以修改 |
异常 | 可以减少或删除,一定不能抛出新的或更广的异常 | 可以修改 |
访问 | 一定不能做出更严格的限制,可以降低限制 | 可以修改 |
类型 | 动态绑定,运行时确定 | 静态分配,类加载时确定 |
追问1:多态含义?
- 1)含义 & 作用
多态是同一个行为(接口、消息)可根据对象不同而采取多种不同行为。能消除类型间耦合,具有良好的可扩展性。
- 2)实现方式 & 必要条件
实现方式:重写、接口(插座)、抽象类和抽象方法。
三个必要条件:继承、重写、父类引用指向子类对[Parent p = new Child();
]
// 例1:
package objectandclass;
class A {
public void show(D obj){
System.out.println("A and D");
}
public void show(A obj){
System.out.println ("A and A");
}
}
class B extends A{
public void show(B obj){
System.out.println("B and B");
}
public void show(A obj){
System.out.println("B and A");
}
}
class C extends B{}
class D extends B{}
}
... {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
a1.show(b); // A and A
a1.show(c); // A and A
a1.show(d); // A and D
a2.show(b); // B and A
a2.show(c); // B and A
a2.show(d); // A and D
b.show(b); // B and B
b.show(c); // B and B
b.show(d); // A and D
}
7、Exception和Error有什么区别?【第2讲】:Throwable类;可预料VS不可恢复;可检查+不可检查
1)相同
- Exception和Error都继承了Throwable类,只有Throwable实例可被抛出(throw) 或捕获 (catch)。
2)解释
- Exception是可预料的意外情况,可能且应该被捕获处理;
- Error是正常不太可能出现的情况,大部分出现会导致程序(如JVM)处于不可恢复异常状态,不便于也不需捕获。
3)Exception分类:
- Exception分为可检查异常和不可检查异常,可检查异常在源代码中必须显式地进行处理,这是编译期检查的一部分;不检查异常(NullXXX、ArrayIndexOutofBoundsXXX),通常是可避免的逻辑错误,根据需要捕获。
追问1:你了解哪些 Error、Exception 或者 RuntimeException?
……
追问2:NoClassDefFoundError 和 ClassNotFoundException 有什么区别?
NoClassDefFoundError是一个错误(Error),而ClassNOtFoundException 是一个异常。
- 1)NoClassDefFoundError:编译时存在,JVM或ClassLoader实例加载(正常调用或new新对象)时找不到类定义,那此时会抛出NoClassDefFoundError;
- 2)ClassNotFoundException:动态加载类在类路径中没找到,此时会抛出ClassNotFoundException异常。
追问3:异常处理有哪些原则?
1)捕获特定异常。 尽量不要捕获通用异常,如 Exception。【基本】
2)不要生吞异常。 可能导致难诊断的诡异情况。【基本】
3) Throw early, catch late 原则。
补充:
1. 不捕获某些异常。如RuntimeException 被扩散出来,而不是被捕获。除非深思熟虑,否则不要捕获 Throwable 或者 Error,这样很难保证我们能够正确程序处理 OutOfMemoryError。
2. 分布式系统最好使用产品日志,详细地输出到日志系统里,printStackTrace()无法找到堆栈轨迹(stacktrace)。
8、谈谈final、finally、 finalize有什么不同?【第3讲】(*2)
- 1)final可以修饰类/变量/方法,代表不可继承/修改/重写;
- 2)finally保证重点代码一定执行的一种机制。
如try-catch-finally关闭JDBC连接、unlock锁
; - 3)finalize为了保证对象在垃圾收集前完成特定资源的回收。JDK 9标记弃用。
追问1:final与immutable相同吗?
答:不等同,只保证对象引用不可赋值,但对象行为(如添加)不被影响。
final List<String> strList = new ArrayList<>();
strList.add("Hello");
strList.add("world");
List<String> unmodifiableStrList = List.of("hello", "world"); // List.of本身不可变
unmodifiableStrList.add("again"); // 会抛出错误
说明:
final 只约束 strList 引用不可被赋值,但 strList 对象行为不被 final 影响,添加等操作正常。若希望对象本身不可变,需要相应类支持不可变行为。
9、String、StringBuffer、StringBuilder有什么区别?【第5讲】(*3)不可变,中间对象;线程安全;非线程安全
String 提供构造和管理字符串的基本逻辑,是典型 Immutable
类。所有类、属性是 final,拼接、裁剪等动作会产生新 String 对象。
StringBuffer 是为减少中间对象而提供的类,可用 append/add
把添加字符串,线程安全。StringBuilder 非线程安全,其他和 StringBuffer 相同,大部分情况首选。
追问1:String是基本数据类型吗?
不是,String是一个类。
- 补充
- 1)整数:byte, short, int, long(
分别是8、16、32、64位
) - 2)浮点:double, float
- 3)逻辑:boolean
- 4)文本:char
追问2:StringBuffer为什么线程安全?
因为加了synchronized。
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
10、int和Integer有什么区别?【第7讲】(*2):包,自动装箱拆箱、值缓存,较小数值范围
- 1)int 是 Java 8 个原始数据类型之一。
- 2)Integer 是 int 的包装类,有 int 字段存储数据,并提供基本操作,如运算、转换等。在Java 5 引入自动装箱和自动拆箱功能(原始类型<=转换=>对象);值缓存(valueOf方法)带来了明显的性能改进。
补充:
1、原始数据类型不是对象。
2、实践发现大部分数据操作都是集中在较小的有限范围,所以引入值缓存,范围:[-128-127]。
二、参考
1、Java基础:static方法与非static方法的区别
2、Java高级特性入门——泛型、反射和注解
3、java提高篇(九)-----实现多重继承
4、Java 8 默认方法和多继承
5、Java重写和重载的区别
6、JAVA重写和重载
7、Java 重写(Override)与重载(Overload)
8、一篇文章让你彻底了解Java内部类
9、Java内部类和匿名内部类的用法
10、java中的匿名内部类总结
11、ClassNotFoundException和NoClassDefFoundError的区别