【Java笔记】笔记记录(一)

笔记记录(一)

Java基础知识复习

一:不可变类

定义:一个类的对象被创建出来以后,它的值便不能被修改了,类似于常量。

常见问题:String类是一个不可变类,那么为什么可以对String对象进行操作呢?

表面上看String对象值是修改了,其实不是,String s = "Hello"声明了一个指向String类型对象的引用,这个引用的名字为s,它指向了一个字符串常量"Hello"。s= s+"World"并没有改变所指向的对象,这句代码运行后,s指向了另一个String类型的对象,该对象的内容为"HelloWorld",原来那个对象还在内存中,没有被改变。

另外:String str = new String("Hello")会发生什么呢?

首先在堆(内存)中创建一个指定的对象,并返回给str,然后在字符串常量池中查找有没有值为"Hello"的对象,如果有,则将new出来的对象与常量池中的对象联系起来,如果不存在,则在字符串常量池中创建一个内容为“Hello”的字符串对象,并联系起来。

总之,new出来的对象指向的是内存中的地址而不是常量池中的地址。

如何创建一个不可变类呢?

1)类中的所有成员变量被private修饰

2)类中没有改写成员变量的方法

3)确保类中的方法不会被之类覆盖,可以通过final实现

4)如果成员变量是引用类型,要确保这个变量的值不发生变化,可以通过clone方法将对象复制

引申:为什么存储密码时用数组比用String类型安全?

因为String是不可变类,它存储在字符串常量池中,就算这个字符串不再被使用,它还是会在常量池中存在一段时间,此时,有权限访问常量池的程序都可能访问到这个字符串,从而造成泄露。

二:值传递和引用传递

对于StringBuild和StringBuffer来说,如果new了一个对象,并创建一个方法将这个对象传入并使用append方法在对象后面加值,你会发现对象的值发生了变化,从而判断这二者是引用传递,因为在方法体中改变了原来的值,但是你如果在方法体中将这个对象重新new一个值,你会发现之前的对象的值没有发生变化,从这个角度上看,它们的本质还是值传递,其实,在第一种传递时,这个方法是创建了一个新的对象,并将形参对象指向这个新的对象,由于指向同一个内存空间,原来的实参对象的指向也发生了变化。

而在第二种方式中,只是形参的指向发生了变化,所以原来实参并不会变化。

三:Java关键字

static:

作用:为某特定的数据类型或对象分配单一的存储空间,而与创建的对象个数无关,并且实现某个方法或属性与类而不是对象关联在一起,于是可以不创建对象直接调用该方法。

也就是说被static修饰的代码块只会运行一次。

可以修饰的元素:

变量:静态变量,可以跨越代码块访问

方法:静态方法,可以跨越代码块进行访问

代码块:静态代码块,只能定义在类定义下,在类被加载时执行

导入包:静态导入包,导入指定的static变量,import static xxx.*;导入该包下的所有static变量

final:

作用:用于声明属性、方法和类,分别表示属性不可变,方法不可覆盖,类不可被继承。

注意:final指的不可变时引用不可变,而不关心实际对象的内容变化。

问题:为什么匿名内部类只能使用成员变量或者被final修饰的局部变量?

因为匿名内部类的代码可能会延迟执行,在外部的方法体的变量都消亡时,只有被final修饰的变量会在匿名内部类中有一个引用的副本。

transient:

作用:当持久化一个对象的时候,可能并不想持久化这个对象的所有属性,这时使用transient修饰的属性不会被持久化。

引申:如何实现序列化?

实现Serializable接口,它里面没有任何方法,你需要使用一个输出流来构造一个对象流对象,使用该对象流的writeObject方法将对象写出,同理恢复这个对象时要使用输入流。

序列化的特点:

1、如果一个对象能被序列化,那么他们的之类也能够被序列号

2、声明为static和transient不能被序列化,因为transient代表对象的临时数据,static代表类成员

3、子类实现了Serializable接口父类没有,子类可以被序列化,父类不行。

volatile:

作用:该字段用于修饰会被多线程访问的属性,以保持该属性的修改对所有线程可见。

相比较与synchronized,它仅用于修饰字段,并且volatile只能保持线程安全三要素中的可见性和有序性,不能保证操作的原子性。

可见性:对于共享变量,一个线程对共享变量的修改,其它线程能够立刻看到。

有序性:代码按照顺序执行

原子性:要么全部执行,要么全部不执行

实现原理:

当一个volatile字段被修改,JVM会立刻执行一个Write-Barrier操作,将当前处理器缓存的数据写会系统内存,并且使其它cpu核心里引用了该地址的数据变成脏数据。

当读取时,JVM会多执行一个Read-Barrier指令,如果该数据已经变脏,那么从主存中重新获取数据。

四:多重继承

Java本身并不支持多重继承,但是可以通过其他方法间接实现多重继承,具体有以下两个方法:

1)通过接口实现

class Duck extends Animal implements CanFly,CanRun{

}

2)通过内部类实现

在一个类中定义一些内部类,让这些内部类继承不同的父类。

class A{

class C extends B{}

class D extends E{}

}

五:反射

反射主要实现了以下功能:

1)获取类的访问能修饰符、方法、属性以及父类信息。

2)在运行时根据类的名字创建对象。在运行时调用任意一个对象的方法

3)在运行时判断一个对象属于哪个类

4)生成动态代理

重要的类:

Class类:

获取方法:

xxx.Class; 不执行静态代码块和动态构造块。

Class.forName("xxx");只执行静态代码块。

new xxx().getClass()执行静态代码块和动态构造块。

此类里的方法主要有三类:

获取类的构造方法

getConstructors()返回全部public构造方法

getConstructor(Class<?>... parameterTypes)返回指定的public构造方法

getDeclareConstructors()返回全部构造方法

getDeclareConstructor(Class<?>... parameterTypes)返回指定的构造方法

获取类的成员变量

getFields();获得全部public成员变量

getField(String name);获得指定public成员变量

getDeclareFields();获得全部成员变量

getDeclareField(String name);获得指定车关于变量

获取类的方法

getMethods();获得public方法

getMethod(String name,Class<?>... parameterTypes);获得指定public方法

getDeclareMethods();获得全部方法

getDeclareMethod(String name,Class<?>... parameterTypes);获得指定方法

六:嵌套类

内部类分为四种:

静态内部类:不依赖外部类实例而被实例化,静态内部类不能访问外部类的普通成员变量,只能访问静态成员和静态方法

class A{

static class inner{}

}

成员内部类

class A{

class inner{}

}

局部内部类

class A{

public void method(){

class inner{}

}

}

匿名内部类:没有类名,没有构造函数,但是必须继承其他类或实现其它接口,好处时更加简洁、紧凑,但带来的问题是易读性下降。

匿名内部类不能有构造函数

不能定义静态成员、方法、类

不能是public、protected、private、static

只能创建匿名内部类的一个实例

一个匿名内部类一定是在new后面

public class MyFrame extends Frame{

public MyFrame(){

addWindowListener(new WindowAdapter(){

 

});

}

}



posted @ 2020-09-12 20:40  枫叶藏在眼眸  阅读(119)  评论(0)    收藏  举报