Java中对象初始化顺序是怎样的
- 先静态,后动态;(静态变量优先于非静态变量初始化)
- 先静态代码块;(在类中有 static 代码块,无论写在哪,都先执行static代码块,有多个的话,按顺序执行,即使 static 代码块在 main 方法后,也会先执行 static 代码块)
- 先父后子;(父类优先于子类初始化)
- 按定义顺序执行;(其他的按定义顺序执行)
作用域和可见性
作用于与可见性 | 当前类 | 同package | 子类 | 其他package |
---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ |
private | ✅ | ❌ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
default | ✅ | ✅ | ❌ | ❌ |
Java 关键字 volatile、transient、final、static
- volatile 标记的成员,每次强制从内存中读取,而不使用任何硬件中的缓存,被 volatile 修饰的成员,在
任何线程
任何时刻
访问都是相同的值; - transient 标记的成员,在序列化中,不会被序列化;
- final 标记的成员,被赋值后,不能被重新赋值;
- final 标记的类,不能被继承;
- final 标记的方法,不能被重写(override);
- static 标记成员(类,方法,域)不属于任何一个对象实例;
Java 的多态
-
Java的多态是通过 接口、继承、重载、重写 实现的
-
继承: A
is a
B -
组合: A
has a
B -
重载(Overload)和覆盖/重写(Override)的区别:
重载:是在同一个类里,在: 方法返回类型、方法参数 不同,但 方法名相同。
重写:是子类,重写父类定义的方法(返回类型,方法名,参数均一样)
抽象类 和 接口 的异同
- 相同:
- 二者均不能被实例化;
- 二者的实现类,必须完全实现了二者中定义的抽象方法/接口方法;
- 不同:
- 接口中没有任何实现的方法体,而抽象类里,可以有实现的方法;
- 接口可以被 implement,抽象类只能被 extends,Java支持多 implement,不支持多 extends;
- 接口强调特定功能的实现,其设计理念是 “has-a” 的关系;集成强调的是所属关系,其设计理念是 “is-a”;
- 接口中的成员变量,默认是 public static final,而抽象类在这方面和普通类差别不大,可以有自己的成员变量,可以有自己的方法体,成员默认的可见性是 default,也可以是 private,public,protected。
抽象类中的抽象方法(abstract)不能用 private,static,synchronized,native 修饰
Switch
switch 的对象,必须是一个 整数
或者一个 枚举
Java 1.7 后,switch 可以针对 String 做。
当对象是 String 时,具体实现是,先去检查 hashCode,然后如果有匹配的项,再检查 equals。
内部类
内部类的意义:
- 在不改变外部类形态的同时,提供对其他
接口
或继承
的特性支持(用内部类去实现or继承)- 在满足第一条的同时,又不丧失灵活性。因为
每一个内部类都能独立地继承自一个(接口的)实现,无论外部类是否已经继承了某个(接口的)实现,对内部类都没有影响
。
成员内部类/普通内部类
public class MemberInnerClass {
public static void main(String[] args) {
OuterClass oc = new OuterClass("aaa", "bbb");
System.out.println(oc);
InnerClass inner = oc.getInner();
System.out.println(inner);
InnerClass inner2 = oc.new InnerClass(); //用 oc.new 才能new一个InnerClass
inner2.setTitle("2222");
oc.setInner(inner2);
System.out.println(oc);
System.out.println(inner2.getOuter()); //不能直接用this,要用 OuterClass.this
}
}
class OuterClass {
private String name;
private InnerClass inner;
public OuterClass(String name, String title) {
this.name = name;
this.inner = new InnerClass();
inner.setTitle(title);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public InnerClass getInner() {
return inner;
}
public void setInner(InnerClass inner) {
this.inner = inner;
}
@Override
public String toString() {
return "OuterClass{" + "name='" + name + '\'' + ", inner=" + inner + '}';
}
class InnerClass {
private String title;
public OuterClass getOuter() {
return OuterClass.this;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return "innerClass{" + "title='" + title + '\'' + '}';
}
}
}
嵌套类/静态内部类
public class StaticMemberClassMain {
public static void main(String[] args) {
StaticMemberClass.StaticInner si = new StaticInner(); //可以直接引用
}
}
class StaticMemberClass {
public static class StaticInner {
}
}
匿名内部类
public class AnonymousClass {
public static void main(String[] args) {
Outer outer = new Outer("Nested");
outer.asyncHello();
}
}
class Outer {
private String name;
Outer(String name) {
this.name = name;
}
void asyncHello() {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello, " + Outer.this.name);
}
};
new Thread(r).start();
}
}
String,StringBuffer,StringBuilder的区别
- String 是不可变的;StringBuffer 和 StringBuilder 是可变的;
//当执行:
String s = "Hello";
s += " World!";
//相当于执行了:
//效率低很多
String s = "Hello";
StringBuffer sb = new StringBuffer(s);
sb.append(" World!");
s = sb.toString();
-
StringBuffer 线程安全;StringBuilder 非线程安全;
-
效率: StringBuilder > StringBuffer > String
TODO
- HashMap,HashTable,ConcurrentHashMap的原理和区别