复习准备秋招,内容有错的地方请各位看官评论区留言!不胜感激!
整体内容在来自作者从网上整理!
Java基础
文章目录
面向对象和面向过程的区别
面向对象易维护,易复用,易扩展。面向对象有封装、继承、多态的特性,可以设计出低耦合的系统,使系统更加灵活,易于维护。但性能比面向过程低。
面向过程性能比面向对象高。因为类调用时需要实例化,开销比较大。比较消耗资源,所以当性能是重要的考虑因素时,比如单片机/Linux等。
Java语言的特点
简单易学
面向对象(三大特性)
平台无关性(JVM)
安全性(不直接操作内存)
支持多线程
网络编程方便
编译与解释并存
Java和C++对比
都是面向对象的语言,都支持封装、继承、多态
Java不提供指针来直接访问内存,程序内存更安全
Java的类是单继承的,C++支持多重继承;Java中的接口可以多继承
Java有自动内存管理机制,不需要程序员手动释放无用内存(GC)
C语言中,字符串或字符数组最后都有一个额外的字符’\0’来表示结束。Java中没有结束符这一概念。
面向对象三大特性
-
封装
封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,则可以不提供方法给外界访问。
-
继承
继承是使用已存在的类作为基础,建立新类的技术。新类的定义可以增加新的数据或者新的功能,也可以使用父类的功能,但不能选择性地集成父类。
通过使用继承可以方便地复用以前的代码。
注意:
子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但父类中的私有属性和私有方法是子类无法访问的,只是拥有。
子类可以拥有自己的属性和方法,即对父类进行扩展
子类可以用自己的方式实现父类的方法。 -
多态
指程序中定义的引用变量所指向的具体类型和通过改引用变量发出的方法调用在程序编译时并不确定,而是在程序运行期间才决定。
即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须由程序在运行期间才能决定。-
重载
同样的一个方法能过根据输入数据的不同,做出不同的处理。
发生在同一个类中,方法名必须相同,参数类型不同,个数不同,顺序不同,方法返回值不同和访问修饰符可以不同。 -
重写
重写发生在运行期,是子类对父类运行访问的方法的实现过程进行重新编写。
返回值类型,方法名,参数列表必须相同。抛出的异常范围必须小于等于父类,访问修饰符范围大于等于父类。
如果父类方法访问修饰符为 private/final/static ,则子类就不能重写该方法,但是被static修饰的方法可以被再次声明。 -
两种方式实现多态:继承和接口
-
构造器
-
构造器不能重写,但可以重载
-
三个特性
- 名字与类名相同
- 没有返回值,但不能用void声明构造函数
- 生成类的对象时自动执行,无需调用
-
作用
-
完成对类的初始化工作
在调用子类构造方法之前会先调用父类没有参数的构造器,其目的是:帮助子类做初始化工作
-
关键字
-
权限修饰符
- public——任何地方
- protected——子类,同一个包,类内部
- 缺省(defaul)——同一个包,类内部
- private——类内部
-
引用相关
-
this
1.可以用来修饰属性,方法,构造器
2.this理解为当前对象或当前正在创建的对象
3.可以在构造器中通过“this()”的方式显示的调用本类中其他重载的指定的构造器。 -
super
-
-
final
被final修饰变量不能被再次赋值
对于final域,编译器和处理器要遵守两个重排序规则:
写final域重排序规则:
禁止把final域的写入重排序到构造函数外部
编译器会在final域的写之后,构造函数return之前,插入一个StoreStore屏障
读final域的重排序规则:
在一个线程中,初次读对象引用与初次读该对象包含的final域,JMM禁止处理器重排序这两个操作。编译器会在读final域操作之前插入一个LoadLoad屏障-
类
-
被final修饰的类不能被继承
final类中的所有成员方法都会被隐式的指定为final方法
-
-
变量
-
基本数据类型
变量一但赋值便不能修改
-
引用数据类型
初始化之后就不能让其指向另一个对象
-
-
方法
-
-
static
被static修饰的变量/方法属于类变量/类方法,可以通过类名.变量名/类名.方法名直接引用,而不需要new出一个类来。
被static修饰的变量、被static修饰的方法统一属于类的静态资源,是类实例之间共享的,换言之,一处变、处处变。-
修饰方法
-
修饰变量
-
修饰代码块
在类初次被加载的时候,会按照static块的顺序来依次执行每个static块,并且只会执行一次。
静态代码块一般用来优化程序性能。 -
静态变量和非静态变量的区别
静态变量被所有对象共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
-
-
transient
被transient修饰的变量不参与序列化和反序列化
String
-
特点
- final修饰的类,底层是final char[]
-
对比
-
String
继承自AbstractStringBuilder,底层用char[] value,但是没有final修饰,是可变的。
由于其不可变,因此是线程安全的。 -
StringBuffer
继承自AbstractStringBuilder,底层用char[] value,但是没有final修饰,是可变的。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,是线程安全的。
效率比StringBuilder低。 -
StringBuilder
继承自AbstractStringBuilder。底层也是char[] value。
未在操作前加同步锁,不是线程安全的。
效率比StringBuffer高。
-
-
一些方法
- String.intern()
包装类
-
装箱
将基本类型用它们对应的引用类型包装起来
-
拆箱
将包装类型转化为基本数据类型
基本数据类型
byte short int long float double char boolean -
原理
从反编译得到的字节码内容可知:
在装箱的时候自动调用的是Integer的valueOf(int)方法。
在拆箱的时候自动调用的是Integer的intValue方法。
Object类方法
-
hashcode()
-
getClass()
-
finalize()
-
equals
- ==与equals的区别
- equals与hashcode()联系
-
toString()
-
clone()
-
线程相关
-
wait()
使一个线程处于等待(阻塞)状态,并且释放当前所持有的锁
-
对比sleep()
sleep: 使一个正在运行的线程处于睡眠状态,使一个静态方法。调用此方法时需要处理InteruptedException异常。
对比:
两者都可以暂停线程的执行
类的不同:
wait是Object类的方法
sleep是Thread线程类的静态方法
是否释放锁:
wait释放锁
sleep不释放锁
用途不同:
wait通常用于线程间交互/通信
sleep通常用于暂停线程
用法不同:
wait方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify/notifyAll方法。(wait(long timepout) 超时后会自动苏醒)
sleep完成后,线程会自动苏醒。
-
-
notify()
唤醒一个处于等待状态的线程。在调用此方法时,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪一个线程,并且与优先级无关。
-
notifyAll()
唤醒所有处于等待的线程。该方法并不是将对象的锁给所有线程,而是让他们竞争,只有获取到锁的线程才进入就绪状态。
-
接口和抽象类
-
继承
Java的接口支持多继承,一个类可以实现多个接口。
抽象类只支持单继承,子类必须实现父类的抽象方法,否则子类也必须定义为抽象类。 -
构造方法
接口没有构造器,但抽象类可以有构造器
-
变量、方法
接口:
变量被隐式指定为 public static final ,必须赋初值,不能修改
方法被隐式指定为 public abstract
抽象类:
变量默认使用 default 修饰,可以在子类中被重新定义,也可以重新赋值
抽象方法被 abstract 修饰,不能被 private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。 -
区别
相同点:
接口和抽象类都不能被实例化
接口的实现类和抽象类的子类都只有实现了接口的或抽象类中的方法之后才能被实例化。
不同点:
接口只有方法的定义,不能有方法的实现。抽象类中可以有普通方法的下定义与实现。
实现接口的关键字为 implements ,继承抽象类的关键字为 extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。使用接口可以间接实现多重继承。
接口强调功能的实现,抽象类强调所属关系。
变量和方法的权限不一样。
接口中变量是 public static final 的,方法是 public abstract 的。
抽象类中的变量默认是 default 修饰的,可以重新定义/赋值。方法被 abstract 修饰,不能被 private、static、synchronized、native修饰。必须以分号结尾,不带花括号。
Java异常机制
-
Error
-
Exception
-
运行时异常RunTimeException
JVM运行期间可能出现的异常。
Java编译器不会检查它。也就是说当程序中可以能出现这类异常时,倘若没有 throws / try-catch-finally 捕获它,还是会编译通过,JVM会自动抛出并自动捕获。 -
编译时异常(受检异常)
Exception除RunTimeException及其子类之外的异常。
特点:
Java编译器会检查它,如果程序中出现此类异常,如:ClassNotFoundException,要么通过 throws 进行声明抛出或者 try-catch-finally ,否则不能通过编译。需要手动捕获。
-
-
区别
–Error类型的错误通常称为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等。编译器不会对这了错误进行检测,Java应用程序也不应捕获这类错误,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复。
–Exception类的错误是可以在应用程序中进行捕获并处理的,通常要对这类错误进行处理,使程序可正常执行。
反射
-
概述
指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法。这种动态获取信息,以及动态调用对象方法的功能叫Java语言的反射机制。
-
原理
-
优缺点
优点:
反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。
缺点:
性能问题。Java反射机制中包含了一些动态类型,所以Java虚拟机不能够对这些动态代码进行优化。因此,反射操作的效率要比正常操作效率低很多。
安全限制。使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。
程序健壮性。反射允许代码执行一些通常不被允许的操作,所以使用反射有可能会导致意想不到的后果。 -
动态代理
泛型
-
为什么要有泛型
1.解决元素存储的安全问题
2.解决获取数据元素时,需要类型强转的问题
枚举
深浅拷贝
JAVA 深浅拷贝的解析_千里之外的博客-优快云博客_java深浅拷贝
-
引用拷贝
创建一个指向对象的引用变量的拷贝。
-
浅拷贝
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。
-
深拷贝
深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。
当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
简而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
IO流分类
- BIO
- NIO
- AIO