面向对象三大特性
- 封装
- 继承
- 多态
多态有什么好处
什么是多态?
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用基类的引用指向子类的对象。
为什么要用多态?
封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态除了代码的复用性外,还可以解决项目中紧偶合的问题,提高程序的可扩展性。耦合度讲的是模块与模块之间,代码与代码之间的关联度,通过对系统的分析把他分解成一个一个子模块,子模块提供稳定的接口,达到降低系统耦合度的目的,模块与模块之间尽量使用模块接口访问,而不是随意引用其他模块的成员变量。
多态的好处
- 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。// 继承
- 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 // 多态的真正作用
实现多态的方式
- 实现接口
- 继承父类,重写父类方法;或继承的是抽象类,实现抽象方法
- 同一个类中,方法重载
创建对象实例的方式有哪些?
使用
new
关键字User user = new User();
使用反射机制
// 方法1
User user = (User) Class.forName("package.User").newInstance();
// 方法2
User user = User.class.newInstance();
// 调用构造方法
Constructor<User> constructor = User.class.getConstructor();
User user = constructor.newInstance();使用
clone
方法public class CloneTest {
// clone 被 protected 修饰
public static void main(String[] args) {
CloneTest cloneTest = new CloneTest();
try {
CloneTest copy = (CloneTest) cloneTest.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}使用反序列化
import java.io.*;
public class SerializableDemo {
public static void main(String[] args) {
// Initializes The Object
User user = new User("Leo");
System.out.println(user);
// Write Obj to File(序列化)
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("tempFile"))) {
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
}
// Read Obj from File(反序列化)
File file = new File("tempFile");
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(file))) {
User newUser = (User) ois.readObject();
System.out.println(newUser);
if (!file.delete()) {
throw new RuntimeException("无法删除该文件:" + file);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class User implements Serializable {
private static final long serialVersionUID = 1565116950906132146L;
private String name;
User(String name) {
this.name = name;
}
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
double 和 BigDecimal 比较
BigDecimal
的缺点:
- 占用更多内存;
- 与基本类型相比,不能使用数学运算符,计算方式更复杂;
- 执行效率慢。
BigDecimal
的优点:
- 精度更高,避免出现
double
运算精度异常的问题; - 更灵活和方便的小数点处理(支持多种舍入模式)。
IO 和 NIO 比较
IO | NIO |
---|---|
面向流 | 面向缓冲区、基于通道 |
阻塞 IO | 非阻塞 IO |
无 | 选择器(Selectors) |
Hashtable 和 HashMap 比较
HashMap
可以插入key
或value
为null
的Entry
;HashMap
把Hashtable
的contains
方法移除了,改成containsValue
和containsKey
。因为contains
方法容易让人引起误解;HashTable
的迭代器是fail-fast
迭代器;HashMap
不能保证随着时间的推移 Map 中的元素次序是不变的。HashTable
的方法均使用synchronized
修饰。
HashMap 的扩容策略
三个关键参数
参数 | 含义 |
---|---|
capacity | table 容量大小,默认为 16。且必须保证该值为 2 的 n 次方 |
size | 键值对的数量 |
threshold | size 的临界值,当 size 大于等于 threshold 就必须进行扩容操作 |
loadFactor | 装载因子,table 能够使用的比例,threshold=capacity*loadFactor |
当需要扩容时,capacity
将变为原来的两倍。
介绍下红黑树
红黑树是一种自平衡二叉查找树。它可以在O(log n)
时间内完成查找、插入和删除,这里 n 是树中元素的数目。
红黑树相对于AVL树来说,牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要优于AVL树。
红黑树还不了解,待补充……
自定义注解
四种元注解
名称 | 作用 |
---|---|
@Target | 描述注解的作用目标 |
@Retention | 需要在什么级别保存该注解信息,用于描述注解的生命周期 |
@Documented | 表明注解包含在 Javadoc 生成的文档中 |
@Inherited | 表明注解可以被继承 |
@Target
的作用目标包括:
ElementType.TYPE
:接口、类、枚举、注解ElementType.FIELD
:字段、枚举的常量ElementType.METHOD
:方法ElementType.PARAMETER
:方法参数ElementType.CONSTRUCTOR
:构造函数ElementType.LOCAL_VARIABLE
:局部变量ElementType.ANNOTATION_TYPE
:注解ElementType.PACKAGE
:包
@Retention
注解的保留策略包括:
RetentionPolicy.SOURCE
:仅存在于源码中,在字节码文件中不包含RetentionPolicy.CLASS
:默认。会在字节码文件中存在,但运行时无法获得RetentionPolicy.RUNTIME
:会在字节码文件中存在,运行时可通过反射获取到
自定义注解示例模板
@元注解 |
自定义注解的解析:自己选取一个合适的时机和位置,比如工厂类创建对象实例的方法中,根据反射技术,拿到用户想要创建的对象上的注解,然后根据注解去做相应的初始化工作。再比如校验性注解,在一个校验方法中,传入对象实例,根据反射拿到注解注明的校验信息,然后判断该实例是否合法。
介绍几种常用的设计模式
单例:确保一个类只有一个实例,并提供该实例的全局访问点。
简单工厂:在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。
观察者:定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
代理:控制对其它对象的访问。
其他问题
- 自己项目的一些问题;
- 谈谈职业规划;
- 平常如何学习技术;