Java期末考试复习提纲
仅供参考,如有错误请联系作者指正
- 方法头: 包括方法的修饰符、返回值类型、方法名、形式参数(最后两项是方法签名)
- 方法体: 在Java语言中方法体一个方法中用大括号{}括起来的部分
- 重载(Overload): 一个类中,定义的多个参数名相同但是参数列表不同的方法(签名不同)
- 重写(Override): 子父类中,子类定义的和其从父类继承而来的方法中方法签名完全相同的方法。
实例方法 = 普通方法
类方法 = 静态方法
上转型对象可以访问子类继承或隐藏的成员变量
匿名对象
new Student();//这个也是一个对象,但是没有名字,称为匿名对象
局部和成员变量
成员变量存储在堆内存的对象中
局部变量存储在栈内存的方法中
成员变量随着对象的出现而出现在堆中,随着对象的消失而从堆中消失
局部变量随着方法的运行而出现在栈中,随着方法的弹栈而消失
成员变量因为在堆内存中,所有成员变量具有默认的初始化值
局部变量没有默认的初始化值,必须手动的给其赋值才可以使用。
先后顺序
第一次:静态代码块-非静态代码块-默认构造方法-普通方法
之后:非静态代码块-默认构造方法-普通方法
protected
不同包下,在子类中通过父类引用不可以访问其 protected 方法
不同包下,在子类中通过该子类引用可以访问其 protected 方法还可以通过 super 关键字调用父类中的该方法。
1 | //print是Parent中的protected方法,并且不在同一个包中 |
不同包下,在子类中不能通过另一个子类引用访问共同基类的 protected 方法
对于protected修饰的静态成员,无论是否同一个包,在子类中均可直接访问
在不同包的非子类中则不可访问
继承
构造方法
创建子类对象时,子类总是按层次结构从上到下的顺序调用所有超类的构造函数。如果继承和组合联用,要先构造基类的构造函数,然后调用组合对象的构造函数(组合按照声明的顺序调用)
如果父类没有不带参数的构造方法,则在子类的构造方法中必须明确的告诉调用父类的某个带参数的构造方法,通过super关键字,这条语句还必须出现在构造方法的第一句
变量隐藏
变量隐藏:在子类对父类的继承中,如果子类的成员变量和父类的成员变量同名,此时称为子类隐藏(override)了父类的成员变量。
子类若要引用父类的同名变量:super.变量名
final可以被隐藏,static也能被隐藏,都能被隐藏。
方法覆盖隐藏
覆盖就是子类的方法跟父类的方法具有完全一样的签名和参数
私有方法、静态方法不能被覆盖,如果在子类出现了同签名的方法,就是方法隐藏
用final声明的成员方法是最终方法,最终方法不能被子类覆盖(试图在子类写同名会直接报错)
继承的好处都有啥?
提高代码维护性,可重用性,可扩展性
继承是类实现可重用性和可扩充性的关键持征
减少模块间的接口和界面
但是继承破坏了封装性,导致耦合性变高,但是问题不大
多态
静多态
即在编译时决定调用哪个方法,也称为编译时多态
一般是指方法重载,方法隐藏
方法重载
方法名相同,参数个数、参数类型及参数顺序至少有一个不同
构造方法和静态成员方法都是可以重载,静态成员方法重载后的方法也可以是非静态成员方法。
方法隐藏
傻逼父类静态方法,不会被子类静态方法覆盖,只会被隐藏
1 | public class Parent{ |
动多态
运行时才能确定调用哪个方法,也称为运行时多态,也称为动态联编,也称为动绑定
“覆盖方法、抽象方法和接口” 和动态联编关系紧密
方法覆盖
继承,方法覆盖,父类的引用指向派生类的实例且通过父类的引用调用被覆盖的方法
final方法没法被覆盖
但是他妈的final变量又可以被子类的隐藏,傻逼 Java有病是不是
私有方法、静态方法不能被覆盖,如果在子类出现了同签名的方法,那是方法隐藏;
继承是子类使用父类的方法,而多态则是父类使用子类的方法
抽象类
不能实例化,但可以创建它的引用
抽象方法不能被private、final或static修饰
当类实现了一个接口/继承抽象类,但并没有实现该接口/抽象类的所有方法时,该类必须声明为抽象类,否则出错
抽象类里可以有变量
可以有构造方法
可以有非抽象方法
抽象方法必须在抽象类里
接口
public interface 名字{…}
interface extents interface
class implements interface
定义
接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有方法的实现。接口是抽象方法和常量值的定义的集合
接口是用来实现类间(不相关类)多重继承功能的结构
接口要点
所有的变量都默认是public static final,并且没法改
接口中所有的方法都默认是public abstract的
没有构造方法
一个类可以实现多个接口
接口中的方法体可以由 java 语言书写,也可以由其他语言书写,用其他语言书写时,接口方法需要用 native关键字修饰(牛逼)
类在实现抽象方法时必须显式的使用 public 修饰符
接口回调
把实现某一接口的类创建的对象引用赋给该接口声明的接口变量
该接口变量就可以调用被类实现的接口中的方法。
接口的进化
其实就是一个接口继承了多接口…
抽象类和接口的区别
-
接口中的成员变量和方法只能是public类型的,而抽象类中的成员变量和方法可以处于各种访问级别。
-
接口中的成员变量只能是public、static和final类型的,而在抽象类中可以定义各种类型的实例变量和静态变量。
-
接口中没有构造方法,抽象类中有构造方法。接口中所有方法都是抽象方法,抽象类中可以有非抽象方法,可以没有抽象方法。抽象类比接口包含了更多的实现细节。
转型
向上转型
将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型或者向上映射。
只能调用父类中定义的属性和方法。
用的变量是父类的,方法是父类被子类覆盖的
没法用子类独有的变量/方法
安全
向下转型
一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型
能用子类独有的变量/方法
若直接创建父类对象,无法向下转型!
不安全
不可转会有运行时异常ClassCastException,不是编译时异常!
instanceof
obj instanceof ClassName/InterfaceName
判断是否是某类/接口的实例
设计原则
-
开闭原则:一个软件实体应当对扩展开放,对修改关闭——降低维护风险
-
单一职责原则: 一个类只负责一个功能领域中的相应职责——提高可读性
-
里氏代换原则: 所有引用基类(父类)的地方必须能透明地使用其子类的对象——防止继承泛滥
-
合成复用原则:尽量使用组合或者聚合关系实现代码复用,少使用继承。——降低耦合
-
依赖倒转原则: 抽象不应该依赖于细节, 细节应当依赖于抽象。 换言之, 要针对接口编程, 而不是针对实现编程——利于升级拓展
-
接口隔离原则: 使用多个专门的接口, 而不使用单一的总接口, 即客户端不应该依赖那些它不需要的接口——高聚合低耦合
-
迪米特法则: 一个软件实体应当尽可能少地与其他实体发生相互作用——减少代码臃肿
设计模式
单例
1 | 饿汉 线程安全效率高,可能浪费空间 |
Object类
public final Class<?> getClass(){ }
public int hashCode() { }对地址或者String进行Hash
自己的类:equal和==基本一样
一些系统的类:String、File、Integer、Double,
Equal判断值是否一样,==判断是否是一个实例
Final方法/类
最终方法既不能被覆盖,也不能被重载
final类中的方法都是隐式的final方法,private默认final
abstract和final不能同时使用
简单数据类型常量其值一旦确定,就不能被改变
复合数据类型常量指的是引用不能被改变,而其具体的值是可以改变的
final变量要么就直接赋值,要么就得在代码块或者构造函数中赋值
内部类
在创建实例内部类的实例时,外部类的实例必须已经存在
静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例
局部内部类
只能在当前方法中使用
可访问外部类的所有成员以及方法中用final修饰的内部成员
1 | public class A{ |
匿名类
匿名类就是没有名字的类,是将类和类的方法定义在一个表达式范围里
匿名类本身没有构造方法,但是会调用父类的构造方法
作用:封装类型、直接访问外部类的成员、回调外部类的方法
回调
1 | public interface Adjustable{ |
异常
方法中:
1 | try{ |
方法声明处:
1 | public void method() throws xxx{} |
自定义异常
1 | public class 名字 extends Exception { |
集合
Set
1 | Set<Integer> set = new TreeSet<>( |
SortedSet是一个按照升序排列元素的Set,狗都不用。
List
1 | static List<Food> list = new ArrayList<Food>(); |
Map
1 | Map<Integer, String> map = new TreeMap<>( |
集合对比
Vector & ArrayList
Vector线程安全
ArrayList重速度轻安全,线程非安全
长度需增长时,Vector默认增长一倍,ArrayList增长50%
Hashtable & HashMap
Hashtable线程安全,不允许null值,继承Dictionary类
HashMap线程非安全,允许null值,实现Map接口
Iterator
只能用来遍历喵
Arrays.sort
不会真有人用这玩意吧
1 | Integer[] a = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5}; |
IO
Input/OutputStream:字节流
Reader/Writer:字符流
1 | Scanner scanner = new Scanner(System.in); |
各种流
过滤流类的主要功能是为输入/输出流提供一个通用的接口,提供将流连接在一起的能力,即将一个流连接到另一个流的尾部,这样可以得到满足应用程序要求的很长的输入和输出过滤器。
带缓存的输入流和输出流对应的类是:BufferedInputStream,BufferedOutputStream:快得很呐
回压流:类PushbackInputStream提供了几个unread()方法,把读过的一个或几个字节数据退回到输入流中,当然也可以回压别的字节数据到输入流中。
unread(int b) unread(byte[] b)
打印流PrintStream是非常重要的输出流,在标准输出中经常用到的System.out就是指向PrintStream实例的一个引用
对象流:读取文件中的对象或将对象写入文件中(看下面序列化)
管道流:管道数据流主要用于线程间的通信
文件
1 | //反正我大作业这么写能跑 |
序列化
简单
1 | void serializeBox() throws Exception{ |
多线程
进程?线程?
进程(process)是程序的一次执行过程,是系统运行程序的基本单位。程序是静态的,进程是动态的。系统运行一个程序即是一个进程从创建、运行到消亡的过程
**线程:**比进程更小的执行单位,一个进程中可以包含多个线程
线程优先级:范围 1~10 (10 级)。数值越大,级别越高 setPriority( )
线程方法
start():启动一个线程。
run():线程体,由start()方法调用,run()方法返回时当前线程结束
sleep(int n):使线程睡眠n毫秒
yield():将CPU控制权主动移交到下一个可运行线程
join():方法join()将引起现行线程等待
sleep&yield:都是静态的实例方法
sleep()使线程转入阻塞状态,而yield()使线程转入runnable状态
yield()给相同优先级或更高的线程运行机会,如果当前没有存在相同优先级的线程,则yield()什么都不做
sleep()会有中断异常抛出,而yiled()不抛出任何异常
sleep()方法具有更好的可移植性
wait&sleep
sleep()方法不会释放对象的锁,而wait()\方法进入等待时,可以释放对象的锁
wait,notify和notifyAll都是与同步相关联的方法,只有在synchronized方法中才可以用
1 | class Thread1 extends Thread{ |
1 | class TestThread implements Runnable { |
synchronized
用关synchronized为共享资源加锁,在任何时刻只有一个线程能用
synchronized关键字可以使用在:
①1.一个成员方法上
②2.一个静态方法上
③3.一个语句块上
synchronized(obj)
wait让本线程等待;别的线程notify可以让等待区一个线程准备开始(但是如果有线程用锁,该线程还是会处于BLOCKED状态)notifyAll唤醒所有
wait(xx)可以传入时间,单位毫秒
守护进程
当一个应用程序的所有非守护线程终止运行时,即使仍然有守护线程在运行,应用程序也将终止
只要有一个非守护线程在运行,应用程序就不会终止
用setDaemon() 来将一个线程设为守护线程
Timer
Timer类的schedule(TimerTask task, long delay, long period)方法用来设置定时器需要定时执行的任务
定时器将在delay毫秒以后开始执行task任务(即执行TimerTask实例的run()方法),每隔period毫秒重复执行一次
网络
最常用的传输层的网络通信协议是TCP和UDP.
端口号的范围为0~65535之间,0~1023之间的端口数是用于一些知名的网络服务和应用
利用TCP协议进行通信的两个应用程序是有主从之分的,一个称为服务器程序,一个称为客户机程序,两者的功能和编写方法不大一样
Socket(String host,int port);
socket.getOutputStream();
利用UDP通信的两个程序是平等的,没有主次之分,两个程序的代码可以完全一样
Public DatagramSocket(int port);
Send(DatagramPacket p)方法
Receive(DatagramPacket p)
Public DatagramPacket(byte[] buf,int length);
tcp能提供数据可靠性
udp不能保证数据库可靠性
tcp传输效率比udp低