JAVA知识点

记录JAVA中最基础,但不主动研究,容易忽略的知识点

目录

初始化执行顺序

JAVA文件多个类

标识接口

内部类

getClass()

final

finalize()

static

switch

volatile

strictfp

null

不可变类

面向对象

基本特征

多态实现机制

数据传递

其他

Math中的round()、ceil()和floor()

String

存储方式

==,equals(),hashCode()

String,StringBuffer,StringBuilder

数组

异常处理

finally

异常

Erorr

Exception

IO流

NIO

序列化

serialVersionUID

外部序列化

JAVA平台与内存管理

class执行的两种方式

加载class文件的方式

类加载器

双亲委派机制


初始化执行顺序

  1. 父类静态变量
  2. 父类静态代码块
  3. 子类静态变量
  4. 子类静态代码块
  5. 父类成员变量
  6. 父类成员代码块
  7. 父类构造函数
  8. 子类成员变量
  9. 子类成员代码块
  10. 子类构造函数

JAVA文件多个类

  • 一个Java文件中可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的类名与文件名必须相同。
  • 若这个文件中没有public的类,则文件名随便是一个类的名字即可。

标识接口

没有任何方法申明的接口叫做标识接口(Serializable、Cloneable),充当一个标识的作用。

内部类

静态内部类(不依赖外部类实例化),成员内部类(依赖外部类实例化),局部内部类,匿名内部类

getClass()

Object类的方法,子类无法覆盖,释义:返回此Object运行时类

final

final指的是引用不可变

finalize()

Object类的方法,GC执行时会调用被回收对象的finalize()方法,可以覆盖此方法实现对其他资源的回收(回收时会先调用finalize(),并在下一次回收时真正释放内存)

static

被static修饰的方法不能使用this,super

switch

不管是byte,short,char,还是String(java7支持,hashcode()获取int值),都是被转换成int后做的比较

volatile

被volatile修饰的变量,会直接从主内存中取值,不会使用线程自己的本地内存(缓存)。volatile不能保证操作原子性。

strictfp

strict float point的缩写,指精确浮点,被strictfp修饰的类,浮点计算会按照IEEE754的标准实现。

null

不是Object实例,没有分配内存,表明引用没有指向任何对象。

不可变类

当不可变类被实例化后,对象中的所有成员变量不可修改。所有的包装类型都是不可变类

原则:

  1. 所有成员变量被private修饰
  2. 没有写或修改成员变量的方法,只提供构造函数
  3. 类中方法不会不会被子类覆盖,final实现
  4. 如果一个类成员变量本身是不可变量,在初始化或获取这个成员变量时,使用clone()方法来确保不可变

面向对象

基本特征

  • 抽象:忽略一个主题与当前目标无关的方面,更充分关注到有关的方面(忽略啄木鸟和鹦鹉喙的长短不同,关注都是有喙的,以此抽象出喙,颜色的特征),有过程抽象(行为:都会飞,跑),数据抽象(特征:都有羽毛)。
  • 继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。
  • 封装:指将客观事物抽象成类(通过不同鸟的共同特征,封装成Bird类)。
  • 多态:同一个行为具有多个不同表现形式或形态的能力(同样是+号,3+4实现整数相加,"3"+"4"实现字符串拼接)。

扩展:【组合】,组合和继承都是代码服用的方式,组合是通过再新类中创建原有类的对象,实现服用。

多态实现机制

  • 方法重载,由于重载的参数不同,因此编译时即可确定调用的方法。【编译时多态】
  • 方法重写,基类的引用可以指向子类实例对象,接口引用变量可以指向其实现类实例对象,程序调用方法在运行期才动态绑定。【运行时多态】

只有类中的方法才有多态的概念,成员变量没有多态概念,成员变量的取值取决于定义的变量类型,不取决于创建的对象类型。

数据传递

基本数据类型是值传递,其余类型都是引用传递(引用传递的本质也是值传递,只不过传递的值是对象的地址)

其他

Math中的round()、ceil()和floor()

round():四舍五入,原理是数字加0.5再向下取整

ceil():向上取整,取大于目标数的最小整数值

floor():向下取整,取小于目标数的最大整数值

String

String是不可变类

存储方式

若字符串常量区有指定字符串则直接获取引用,没有则创建。

String s = "abc"; // "abc"放到字符串常量区,s指向它
String s = "a" + "bc" // 转化成"abc"后再放到常量区
s = "def"; // 由于String是不可变类,所以"def"放到字符串常量区,s重新指向它、

String s = new String("abc"); // 在堆中创建一个String对象指向常量区里的"abc"

new String("abc")会创建一个或两个对象,一个是堆里的对象,一个是字符串常量区的对象(不存在时)

==,equals(),hashCode()

  • ==:比较变量对应内存中所存储的值是否相等。因此,引用类型变量里存放的是其对象的地址,仅能比较是否指向同一对象,不能比较内容是否相等。
  • equals():Object类的方法,默认就是==,可被覆盖。String类重写了equals,用于比较对象中的内容是否相等
String s1 = new String("abc");
String s2 = new String("abc");

s1 == s2; // false,变量中的对象地址不同
s1.eqauls(s2); // true
  • hashCode():Object类的方法,将对象地址转化为一个int,可被覆盖。如果不重写,任何两个对象的hashCode()都不等

String,StringBuffer,StringBuilder

  • String:不可变类,适合字符串被大量共享的场景使用
  • StringBuffer:可变类,多线程字符串需要经常被修改时使用,线程安全
  • StringBuilder:可变类,单线程字符串需要经常被修改时使用,线程不安全

效率

String<StringBuffer<StringBuilder

String作为不可变类的修改操作是基于StringBuffer实现

String s = "hello";
s += "world";

// 等价

StringBuffer sb = new StringBuffer(s);
sb.append("hello");
s = sb.toString();

数组

二维数组第二维长度可以不一样

异常处理

finally

  • finally块中的代码在try和catch块的return之前执行
  • finally块中的return会覆盖try和catch块的return

引申:由于在一个方法内部定义的变量都存储在栈中,当这个函数结束后,其对应的栈就会被回收,此时在其方法体中定义的变量将不存在了,因此return在返回时不是直接返回变量的值,而是复制一份,然后返回。所以程序return时会先将返回值存到指定的位置,再执行finally,所以再finally中修改返回值,对基本类型无效,对引用类型有效。

public class Test {

    public static void main(String[] args) {
        System.out.println(Test.returnBase()); // 1
        System.out.println(Test.returnString()); // hello world
    }

    public static int returnBase() {
        int i = 1;
        try {
            return i;
        } catch (Exception e) {
            return 0;
        } finally {
            i++;
        }
    }

    public static StringBuffer returnString() {
        StringBuffer i = new StringBuffer("hello");
        try {
            return i;
        } catch (Exception e) {
            return null;
        } finally {
            i.append(" world");
        }
    }
}

异常

所有异常都继承自(java.lang.Throwable)

Erorr

Erorr表示程序在运行期间出现了严重错误,不可恢复,会导致程序停止(如:OutOfMemoryError)

Exception

可恢复异常,编译器能检查到。有两种

  • 检查异常:所有继承自Exception并且不是运行时异常的异常都是检查异常(IOException,SQLException),编译器会强制在代码中捕获此异常
  • 运行时异常:编译器不会强制捕获,出现运行时异常时,系统会一直把异常向上抛,由JVM处理(NullPointerException,ClassCastException)

IO流

  • 字节流以字节为单位(8bit),不使用缓存
  • 字符流以字符为单位(16bit),使用缓存

JAVAIO类使用了装饰者模式

NIO

JAVA传统通信使用socket,accept和read都有可能会发生阻塞,如果有多个连接,就要用到多线程,每个线程有自己的栈空间,而且由于阻塞会导致大量线程进行上下文切换,使得程序的运行效率非常低下。

NIO(非阻塞IO):Channel,Selector,Buffer来实现

  • Channel:双向(可读可写)的通道
  • Selector:管理Channel,实现时会把Channel的IO事件注册到Selector中,Selector轮询已注册的Channel,发现某个Channel有事件发生,传回Selectionkey(与Channel对应的key),通知程序对对应Channel进行读写
  • Buffer:存放Channel读写的数据

由于轮询比线程的切换效率高,所以并发下NIO执行效率更高

序列化

序列化将对象转化为字节的过程

static,transient修饰的变量不会被序列化

serialVersionUID

用于判断对象是否一致

最好显式声明:

  1. 提高程序运行效率:不声明,系统有自动计算过程
  2. 提高不同平台兼容性:不同平台的JVM,serialVersionUID生成方式不一样,有可能一个平台序列化的对象不能再另一平台反序列化
  3. 提高程序不同版本兼容性:修改类的属性后,计算出的serialVersionUID不一致

外部序列化

实现Externalizable接口,重写方法自定义实现序列化操作。

JAVA平台与内存管理

class执行的两种方式

  • 即时编译:先将字节码编译成机器码,再执行机器码
  • 解释执行:解释器每次解释并执行一小段代码(通常采用)

加载class文件的方式

隐式加载:new等操作时,隐式调用类加载器将类加载到JVM

显式加载:Class.forName

类加载器

BootstrapClassLoader:加载系统类(jre/lib/rt.jar)

ExtClassLoader:加载扩展类(jar/lib/ext/*.jar)

AppClassLoader:加载应用类

双亲委派机制

三个类加载器是协作完成类加载的,具体的实现方式是

  1. 有类需要加载时,类加载器会委托父类进行类加载
  2. 父类按照自己的搜索路径查找需要加载的类,搜索不到,交给子类自己加载

好处

  • 防止重复加载:通过委托,类已经被父类加载过了,就不用再加载。
  • 防止系统级别的类被篡改:系统类一定是被BootstrapClassLoader按自己的路径加载过了,所以自己写一个系统类也不会被加载。

PS:双亲委派其实是并不准确,并不是指有一个父class和母class,java也没有多继承,看网上的看法可能是翻译问题:parents delegate

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值