父类子类构造函数
子类的构造函数会隐式调用父类的无参构造函数,子类若想调用父类的构造函数需在子类的构造函数的第一行使用super调用父类的构造函数。
public class Person {
private String name;
public Person() {
System.out.println("无参构造");
}
public Person(String name) {
this.name = name;
System.out.println("构造函数");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Student extends Person {
private String sex;
private String age;
public Student() { }
public Student(String name, String sex, String age) {
super(name);
this.sex = sex;
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
String、StringBuffer、StringBuilder
String字符串存储在字符串常量区,任何对String进行的修改都会产生一个新的对象,String是final的
StringBuffer和StringBuilder都是可变的,可以对同一个对象进行修改。区别是StringBuilder是线程不安全的,线程使用StringBuffer时会先对其加锁。
类不允许多继承,接口允许多继承
CopyOnWriteArrayList适用于写少读多的并发场景。
ReadWriteLock即为读写锁,他要求写与写之间互斥,读与写之间互斥,读与读之间可以并发执行。在读多写少的情况下可以提高效率。
ConcurrentHashMap是同步的HashMap,读写都加锁。
volatile只保证多线程操作的可见性,不保证原子性。
一个线程执行的过程有三个阶段:
加载(复制)主存数据到操作栈 --> 对操作栈数据进行修改 --> 将操作栈数据写回主存
volatite关键字,让编译器不去优化代码使用缓存等,以保证线程在“加载数据阶段”加载的数据都是最新的
eg:
某一时刻i=6是最新的值,volatile保证线程A,B都同时加载了这个最新的值,
然后A执行i(A)+1=7,然后将7写回主存,
B也执行i(B)+1=7,然后也将7写回内存,
这样,执行两次加法,i却只增加了1
静态分配与动态分配
分配是针对方法而言的,指的是方法确定的过程,根据发生实际分为静态分配和动态分配。
相关的非虚方法和虚方法
非虚方法:指的是在解析阶段可以确定方法的唯一版本,符合的有静态方法、私有方法、构造器、final方法。
虚方法:非私有方法。
静态分配的典型例子是方法的重载。
Person a = new Student()
可以这样来理解,Person是变量a的静态类型,Student是变量a的实际类型,a的静态类型在编译期间就可以确定,而a的实际类型只有在运行期间才可以确定。
对于方法重载而言,方法的签名及方法名都一样,只能通过形参去确定,而形参是在编译期间就能确定的静态类型,即方法重载是通过静态分配确定的。
/**
* 静态分派
*
*/
public class StaticDispatch {
static class Human {
}
static class Man extends Human {
}
static class Women extends Human {
}
public void sayHello(Human guy) {
System.out.println("hello, guy!");
}
public void sayHello(Man guy) {
System.out.println("hello, man!");
}
public void sayHello(Women guy) {
System.out.println("hello, women!");
}
public static void main(String[] args){
Human man = new Man();
Human women = new Women();
StaticDispatch sd = new StaticDispatch();
sd.sayHello(man);
sd.sayHello(women);
}
}
动态分配与另一个特征息息相关,重写
/**
* 动态分派
*
*/
public class DynamicDispatch {
static abstract class Human {
protected abstract void sayHello();
}
static class Man extends Human {
@Override
protected void sayHello() {
System.out.println("hello man!");
}
}
static class Women extends Human {
@Override
protected void sayHello() {
System.out.println("hello women!");
}
}
public static void main(String[] args){
Human man = new Man();
Human women = new Women();
man.sayHello();
women.sayHello();
man = new Women();
man.sayHello();
}
}
其输出会是
hello man!
hello women!
hello women!
类加载过程
加载 ——验证——准备——解析——初始化
加载:通过类的全限定名来获取类的二进制字节流,将字节流的静态存储结构转化为方法区的运行时数据结构,在内存中生成一个代表这个类的java.lang.Class对象作为方法区这个类的各类数据的访问入口。
验证:确保Class文件的字节流符合当前虚拟机的要求,文件格式验证、元数据验证、字节码验证、符号引用验证。
准备:为类变量分配内存并且初始化。
解析:
初始化:执行类构造器<clinit>()
静态块,非静态块,构造方法执行顺序
静态块——非静态块——构造方法
public class StaticBlockTest {
{
System.out.println("normal test");
}
static {
System.out.println("static test");
}
public StaticBlockTest() {
}
public static void main(String[] args) {
StaticBlockTest test = new StaticBlockTest();
StaticBlockTest another = new StaticBlockTest();
}
}
输出结果:
static test
normal test
normal test
another example
public class StaticBlockingTest {
{
System.out.println("构造块");
}
public static StaticBlockingTest a = new StaticBlockingTest();
public static StaticBlockingTest b = new StaticBlockingTest();
static {
System.out.println("静态构造块");
}
public StaticBlockingTest() {
System.out.println("构造函数");
}
public static void main(String[] args) {
StaticBlockingTest c = new StaticBlockingTest();
}
}
输出结果
构造块
构造函数
构造块
构造函数
静态构造块
构造块
构造函数
其结果与其顺序有关
一个类的构造器可以调用该类的其他构造方法
public class Student extends Person {
private String sex;
private String age;
public Student() {
}
public Student(String sex) {
this.sex = sex;
}
public Student(String age, String sex) {
this(sex);
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
引用传递
public class Tester{
public static void main(String[] args){
Integer var1=new Integer(1);
Integer var2=var1;
doSomething(var2);
System.out.print(var1.intValue());
System.out.print(var1==var2);
}
public static void doSomething(Integer integer){
integer=new Integer(2);
}
}
输出
1true