java期末复习

制作不易,有能力的同学,可以简单打赏一下吧,介绍一下我们团队,成员都是来自计算机大一大二的高手,计算机学院所有的课程都可以进行辅导,考前一对一面授,期末上车,免挂科,如果平时学习有困难的,都可进行辅导,发送学校课程笔记,分析历年期末试卷。

mm_facetoface_collect_qrcode_1685964394380

基本语法

知识点一 基本数据类型

基本数据类型
boolean  布尔类型  值:ture 和false
char 字符类型 2个字节
byte  1给字节 范围是(-128到127) 127+1=-128
short  2个字节
int   4个字节
long  8个字节
float  4个字节
double 8个字节

变量命名

首字母是英文字母、$、和下划线,由字母、数字和下划线组成 一般遵循驼峰命令法。不能使用java的关键字。

知识点进制转换

十进制转二进制

十进制转二进制 将十进制不断的除以2,直到商为0,将余数进行倒叙排列,得到二进制数。
 将十进制的15转为二机制;
 15/2=7 余数1
 7/2=3 余数1
 3/2=1 余数1
 1/2=0 余数1 所以转为二进制就是1111;

二进制转十进制

二进制转为十进制要从右到左用二进制的每个数去乘以2的相应次方,小数点后则是从左往右。

位运算

位运算符
按位运算符  两个十进制数运算时都需要先变为二进制,进行二进制的计算,然后在转为十进制
按位与 & 将两个二进制进行与运算,只有两个二进制都为1的时候,结果才为1
按位或 | 只有两个二进制都为0是才为0,有一个为1就是1.
按位异或 ^ 只有两个二进制对应位不同时,结果的对应位才为0;

移位运算

移位运算
>> 右移  >>1相当于除以2
<< 左移  <<1 相当于乘以2

循环语句

for  while  dowhile  if-else  switch-case;
注意 continue 和break的用法和区别。

九九乘法表

public class 九九乘法表 {
    //实现九九乘法表,对for循环的介绍
    public static void main(String[] args) {
        //嵌套双城的for循环
        for (int i = 1; i <=9; i++) {
            for (int j = 1; j <=i; j++) {
                System.out.print(i+"*"+j+"="+i*j+"\t");
            }
            System.out.println();
        }
    }
}

递归 斐波拉契数列

public class 递归斐波拉契数列 {

    public static void main(String[] args) {
        System.out.println(f(5));
    }
    public  static  int f(int n){
        if (n==1||n==2){
            return 1     }
        return  f(n-1)+f(n-2);
    }
}

装箱和拆箱

java基本类型不是对象类型,不符合面向对象的特征,java提供了基本类型的包装类,具有面向对象的特点

需要记忆
int -Integer
char-Character
int->integer 叫做装箱
Integer-> int 叫做装箱

面向对象内容

1.面向对象基本概念

学习面向对象的过程,实际上也是建立面向对象思维的过程。

先整体,再局部。先抽象,再具体,看透事物的本质,用java代码来解释某个事物的行为和特征,将其转变成一个可以被程序理解和调用的实例。

如何建立这种面向对象的思维呢?这里提出一个有趣的问题:这个世界是由什么组成的?

”如果是一个化学家,他也许会告诉你“这个世界是由分子、原子、离子等等的化学物质组成的”。

如果是一个画家呢?他也许会告诉你,“这个世界是由不同的颜色所组成的”。…每个人肯定都有自己的看法,这里就不一一赘述了。

但如果让一个分类学家来考虑问题就有趣的多了,他会告诉你“这个世界是由不同类型的物与事所构成的”好!作为面向对象的程序员来说,我们要站在分类学家的角度去考虑问题!是的,这个世界是由动物、植物等组成的。动物又分为单细胞动物、多细胞动物、哺乳动物等等,哺乳动物又分为人、大象、老虎……就这样的分下去了!

有了这种考虑问题的思维之后,我们来分析一下,什么是人类 ?

首先让我们来看看人类所具有的一些特征,这个特征包括属性(一些参数,数值)以及方法(一些行为,他能干什么!)。每个人都有身高、体重、年龄、血型等等一些属性。人会劳动、人都会直立行走、人会合理的使用工具等等这些方法。

人之所以能区别于其它类型的动物,是因为每个人都具有人类这个群体的属性与方法。“人类”只是一个抽象的概念,它仅仅是一个概念,所有具备“人类”这个群体的属性与方法的对象都叫人!

比如说 亚当、夏娃是具体的人,属于人类,因为他们具有人类的行为和特征。

2.类和对象的关系

定义一个类的对象,其实就是创建一个类的实例,表示一个具体的对象。

格式: 类名 对象名 = new 类名();

例如: 人类 亚当 = new 人类();

左边的这个人类,表示亚当的类型是人类,右边的 new 人类(); 表示亚当是一个具体的实例,拥有人类的行为和特征。

在声明一个具体对象时,如果只声明对象而没有给出具体实例,例如

People p1 =null; 或者 People p2 ;

此时p1 和p2 无法正常使用,因为没有具体的内存指向。

p1 = new People(); p2 = new People();

在有了具体的内存指向后,p1和p2 才可以正常使用。

3类中的成员

类的定义

class 类名 {

(特征)属性名称

例如: int age ; //年龄

(行为)方法名(){ }

例如: void move(){ 直立行走 }

}

在类中描述人类特征的,就是类中的属性,也叫成员属性。在类中描述人类行为的,就是类中的方法,也叫成员方法。

如果要想访问类中的属性或方法则可以依靠以下的语法形式:
访问类中的属性:对象名.成员属性 ;
调用类中的方法:对象名.成员方法();


public class People {
	//类中的成员属性
	int age;//年龄
	String name;//名字
	double lenght;//身高
	
	//类中的成员方法
	public void move() {//移动
		System.out.println("直立行走");
	}
	public void sleep() {
		System.out.println("日出而作日落而息");
	}
	
	public static void main(String[] args) {
		//创建类的实例对象 可以调用类中的属性和方法
		People p1 = new People();//
		p1.name = "亚当";
		p1.age=30;
		p1.lenght=1.85;
		System.out.println("这个人类的名字是"+p1.name);
		System.out.println("这个人类的年龄是"+p1.age);
		System.out.println("这个人类的身高是"+p1.lenght+"m");
		p1.move();
		p1.sleep();
	}
 
}
这个人类的名字是亚当
这个人类的年龄是30
这个人类的身高是1.85m
直立行走
日出而作日落而息

4.类的构造器

类的构造器,也称为构造方法,每个类中都默认存在一个,与类名完全相同,没有返回值类型修饰符(包括void),没有参数的方法。

public class People {
	  public People() {
		//自动产生的构造方法
	}

构造方法的作用,是给类中的成员属性初始化赋值。在类中不允许先声明变量后赋值的情况,一般情况下,都是使用构造方法来给属性赋值,这个过程就是初始化。

构造方法也是类中的方法,支持方法的重载。即方法名相同,参数列表不同。同一个类中可以有多个构造方法,在创建类的对象时, new 类名 () ,这个()实际上就是一个无参构造。也就是说,在创建类的实例对象时,实际上是执行了该类的构造方法。

public class People {
	  public People() {
		System.out.println("我是People类构造器");  
	  }
	
	public static void main(String[] args) {
		People p1 = new People();//执行
		
	}
 
}

注意:当在类中写了有参构造方法后。默认的无参构造将不再生效,创建类的实例对象时,需要根据构造方法传递对应的参数,否则就会报错。

(1)构造方法名称与类名相同,没有返回值声明(包括 void)
(2)构造方法用于初始化数据(属性)
(3)每一个类中都会有一个默认的无参的构造方法
(4)如果类中写了构造方法,那么默认构造方法将无效
(5)如果写了有参构造方法,还想保留默认构造方法,需要显示的写出来。
(6)构造方法可以有多个,但参数不一样,称为构造方法的重载
(7)在构造方法中调用另一个构造方法,使用this(…),该句代码必须在第一句。
(8)构造方法之间的调用,必须要有出口,否则会保错。
(9)给对象初始化数据可以使用构造方法或setter方法,通常情况下,两者都会保留。
(10)一个好的编程习惯是要保留默认的构造方法。(为了方便一些框架代码使用反射来创建对象)。

5堆和栈

创建类的对象 : 类名 对象名 = new 类名();

如果输出这个对象名的话,看到输出的是一串乱码,其实这是这个对象在内存中的地址值。

对象名可以理解为一个引用,储存在栈中。

创建的实例对象 new People是储存在堆中,包含类中全部的属性和方法。

对象名.属性 这个调用属性的过程,实际上就是通过引用地址,找到堆内存中对应数据的过程。
img

6关键字this的作用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7SI0AKt-1687427225575)(C:\Users\周鑫\AppData\Roaming\Typora\typora-user-images\image-20230605194736513.png)]

注意 1.this不能出现在普通方法中,必须出现在构造方法里面

2.必须是构造方法中的第一条语句,构造方法之间的调用必须留出口。否则就是死循环,会报错。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hPzfKPnI-1687427225575)(C:\Users\周鑫\AppData\Roaming\Typora\typora-user-images\image-20230605194855187.png)]

7 静态关键字static

static:静态修饰符
使用static关键字修饰一个属性:该属性就是静态属性,也叫全局变量,类名.属性名可以直接访问
使用static关键字修饰一个方法:该方法就是静态方法,可以不用创建对象,直接类名.方法名调用
声明为static的方法有以下几条限制:
1、静态方法只能调用其他的静态方法,不能调用非静态方法。而在非静态方法中是可以调用静态方法的
2、静态方法中只能访问静态属性
3、静态方法不能引用this或super。
4、不允许用来修饰局部变量

public class People {
	static int a;//静态属性
	int b;//非静态属性
	static void m1() {//静态方法
		a=100;	
		//b=10;//编译错误,不能访问非静态属性
		//m2();//编译错误,不能调用非静态方法
		m3();
	}
	void m2() {//非静态方法
		b=10;
		a=100;
		m3();
	}
	static void m3() {
		
	}

封装

实际上就是信息隐藏,将类中的成员属性和成员方法修饰为私有化,数据被保护在对象的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系,即get/set方法。

其他对象只能通过该对象提供的get/set方法,与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节(当然也无从知道),但可以通过该对象对外提供的接口来访问该对象。

对于封装而言,一个对象它所封装的是自己的属性和方法,所以它不需要依赖其他对象就可以完成自己的操作。使用封装的好处:

1、良好的封装能够减少耦合。

2、类内部的结构可以自由修改。

3、可以对成员进行更精确的控制。

4、隐藏信息,实现细节。

列子

public static void main(String[] args) {
	Dog d1 = new Dog();
	d1.age=3;
	d1.name="旺财";
	}
}
 
class Dog{
	public int age;
	public String name;		
}

如果有很多代码都使用了Dog这个类;当某一天这个类的age属性需要换成String类型,那么,外部使用它的任何地方都需要需改xxx.age=“xxx”,这将是非常繁琐的一个过程,那该怎么办呢?很简单,使用private修饰符将属性封装,开放访问接口的方法,我们只需要修改一下set方法就能完美解决

public static void main(String[] args) {
	Dog d1 = new Dog();
	//调用时发生变化
	d1.setName("旺财");
	d1.setAge(3);
	}
}
class Dog{
	private String age;//修改为String类型
	private String name;
	//将属性私有化,提供set方法,将int类型的值转成String
	public void setAge(int age) {
		this.age = String.valueOf(age);
	}
	public void setName(String name) {
		this.name = name;
	}

这样外部使用它的地方都不用修改,我们只用简单的修改对象内部就可以了,更加方便快捷。到了这里我们应该可以看出,封装确实可以使我们容易地修改类的内部实现,而无需修改使用了该类的客户代码。

这里还可以体现出一些封装属性的优势,案例如下:

public static void main(String[] args) {
	Dog d1 = new Dog();
	d1.setName("旺财");
	d1.setAge(300);//狗的年龄赋值很明显不合理,这里就需要在set方法中给出提示
	}
}
class Dog{
	private String age;
	private String name;
	public void setAge(int age) {
		if(age>100||age<0) {
			System.out.println("你见过超过100岁的狗狗吗?");
		}else  {
			this.age = String.valueOf(age);
		}
		
	}
	public void setName(String name) {
		this.name = name;
	}
		
}

8 特性 继承

继承,通俗点来说就是 子承父业。是使用已存在的类的定义作为基础,建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类中的某些属性,除了父类中私有的属性和方法,子类必须全部继承。

1、被继承的类称为父类(超类),继承父类的类称为子类(派生类)使用 关键字extends 继承。
2、子类拥有父类非 private 的属性、方法。
3、子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
4、子类可以用自己的方式实现父类的方法(即方法的重写/覆盖)。
5、构造器而言,它只能够被调用,而不能被继承,子类可以使用super()调用父类构造器。
6、对于继承而已,子类会默认调用父类的无参构造,但是如果父类没有无参构造,子类必须要在其构造方法中的第一行代码调用指定父类的构造器,传递对应参数。
7、Java 的继承是单继承,但是可以多重继承,即子类只能拥有一个直接父类,但是该父类仍然可以作为其他类的子类。

class Father{
	//父类中的非私有属性都会被继承
	public int age;
	private double money;
	String home;
	//父类中的非私有方法都会被继承
	void eat() {} //吃东西
	public void sleep() {}//睡觉
	private void soner() {}//打呼噜
	//父类构造方法如果有参数,子类必须在构造方法第一行中调用
	public Father(int x) {
		//父类如果写了有参构造,那么默认的无参构造将不再生效
	}
}
class Son extends Father{
 
	public Son(int x) {
		super(x);//调用父类构造 super() 
		age=12;//继承后拥有父类的属性
		home="王者峡谷河道下边的草丛";
		//money=3.0; 父类私有属性无法访问
		sleep();//可以执行父类中的非私有方法
	}
	
}

这里补充一下,子类继承父类,默认在子类构造方法中调用父类构造,在创建子类实例对象时,实际上的执行顺序是(父类构造——子类构造)。在类的构造器中还有一段特别的代码,优先与构造器,在创建对象时优先执行,话不多说直接看代码:
    
    public static void main(String[] args) {
		Z z1 = new Z();//创建子类实例对象时,实际上的执行顺序
	}
	
}
class F {
	static { 
		//静态代码块,只有方法的大括号,没有方法名返回值等任何内容
		System.out.println("父类静态代码块");
	}
	{
		//构造代码块,只有方法的大括号,没有方法名返回值等任何内容
		System.out.println("父类构造代码块");
	}
	public F() {
		// 父类构造器
		System.out.println("父类构造器");
	}
}
class Z extends F{
	static { 
		//静态代码块,只有方法的大括号,没有方法名返回值等任何内容
		System.out.println("子类静态代码块");
	}
	{
		//构造代码块,只有方法的大括号,没有方法名返回值等任何内容
		System.out.println("子类构造代码块");
	}
	public Z() {
		// 父类构造器
		System.out.println("子类构造器");
	}
}父类静态代码块
子类静态代码块
父类构造代码块
父类构造器
子类构造代码块
子类构造器

9.多态

面向对象三大特征,封装、继承、多态。从某种意义上来讲,封装和继承几乎就是为了多态而准备的,也是三大特征中最重要的知识点。

多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。简单来说就是不同类型的对象(父类或子类)调用同一个方法,根据发出调用的对象不同,执行的方法也就不同。

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

多态的作用:消除类型之间的耦合关系。

这里举一个简单的小例子:父类是个农民,技能是使用锄头耕地。子类继承了父类,重写了父类的锄头耕地技能,更新换代为使用拖拉机耕地。如果是父类对象调用这个技能,就是使用锄头手动耕地,如果是子类对象调用这个技能,就是使用拖拉机耕地。

java实现多态有三个必要条件:继承、重写、父类引用指向子类对象。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
父类引用指向子类对象(向上转型):在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

举列

public class People {//人类 作为所有职业的父类
	
	public int age;
	public String name;
	void work() {//父类的方法
		System.out.println("劳动");
	}
	public static void main(String[] args) {
		//父类引用指向子类对象就是多态性的体现
		People p1 = new Doctor();// p1的类型是人类类型,但是指向的实例对象是医生
		p1.work();//父类引用发出的调用,调用到的是医生类中重写父类的方法
		People p2 = new Teacher();
		p2.work();//父类引用发出的调用,调用到的是教师类中重写父类的方法
	}
	
}
 
class Doctor extends People{
	@Override
	void work() {//医生类继承人类,重写工作方法
		System.out.println("救死扶伤");
	}
	
}
class Teacher extends People{
	@Override
	void work() {//教师类继承人类,重写工作方法
		System.out.println("教书育人");
	}
}

多态的好处:

1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如:医生、律师、程序员都是人类的子类,根据使用场景不同随时可以替换为符合的职业。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在拥有了医生、律师的继承上,还可以继续添加新的职业,比如主播,运动员等,都是添加为人类的多态性。
3.接口性(interface-ability)。多态是超类通过抽象方法,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。每个子类都可以根据自身的特性去重写父类的抽象方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

10重载和重写

方法的重载与重写就是方法多态性的一种表现。

重载的规则:

1、必须具有不同的参数列表;

2、可以有不同的返回类型,只要参数列表不同就可以了;

3、可以有不同的访问修饰符;

4、可以抛出不同的异常;

重写方法的规则:

1、参数列表必须完全与被重写的方法相同。

2、返回的类型必须一直与被重写的方法的返回类型相同。

3、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)

4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:

父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常

5、父类的私有方法不能被子类继承,所以不能被重写

6、父类中的方法若使用private、static、final任意修饰符修饰,那么,不能被子类重写。

11 super关键字的作用

可以理解为对父类的引用,super可以完成以下的操作:
1、使用super调用父类中的属性,可以从父类处获得信息。
2、使用super调用父类中的方法,在子类中执行。
3、使用super调用父类中的构造方法(super(实参)形式),必须在子类构造方法的第一条语句,调用父类中相应的构造方法,若不显示的写出来,默认调用父类的无参构造方法,比如:super();

class F {
	public int age;
	public String name;
	void m1() {
		System.out.println("父类方法");
	}
	public F(int age) {
		System.out.println("父类有参构造");
	}
	public F(){
		System.out.println("父类无参构造");
	}
}
class Z extends F{
	public Z() {
		super();//调用父类构造,若不写这行代码也会默认调用父类的无参构造
		//若是调用父类有参构造,则需要传递对应类型的参数
		super.age=30;//调用父类属性
		super.m1();//调用父类方法
	}
}

12final关键字的作用

使用final关键字完成以下的操作:
a、使用final关键字声明一个常量
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化。

	public final int age =10;
	//声明为常量时必须赋值,否则会报错
	public static final String name = "亚当";
	//一般和静态修饰符配合使用,修饰为静态常量,
    //在编译期间知道静态常量的确切值,所以编译器会把它当做编译期常量使用进行优化,字体变成蓝色加粗
	 void work() {//父类的方法,此方法可以被子类重写
		System.out.println("劳动");
	}
	 final void sleep() {
		 //此方法不能被子类重写,但是可以被子类调用
	 }

a.如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的
b、使用final关键字声明一个方法,该方法为最终方法,且只能被子类继承,但是不能被子类重写。
c、使用final关键字声明一个类,该类就转变为最终类,没有子类的类,fianl修饰的类无法被继承。

13接口

Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。接口实现和类继承的规则不同,为了数据的安全,继承时一个类只有一个直接父类,也就是单继承,但是一个类可以实现多个接口,接口弥补了类的不能多继承缺点,继承和接口的双重设计既保持了类的数据安全也变相实现了多继承。

Java接口本身没有任何实现,因为Java接口不涉及表象,而只描述public行为,所以Java接口比Java抽象类更抽象化。但是接口不是类,不能使用new 运算符实例化一个接口。如 x=new comparable(…);//这个是错误来的。但是可以声明接口变量Comparable x; //这是允许的。Java接口的方法只能是抽象的和公开的,Java接口不能有构造器,Java接口可以有public、static和final属性。即接口中的属性可以定义为 public static final int value=5;

public interface Weapon {//声明一个接口
	int HP=100;//接口中定义的变量就是静态常量
	
	void kill();//接口中定义的方法就是抽象方法
	 //当不定义返回值类型时默认public
	//private void m1();//接口中不能定义私有抽象方法,没有意义
	//private int MP=100;//接口中不能定义私有属性
	static void m2() { //接口中可以有具体的方法,必须声明为static或者default
		System.out.println("物理攻击");
	}
 
}
接口的使用规则:
1、定义一个接口,使用interface关键字
2、在一个接口中,只能定义常量、抽象方法,JDK1.8后可以定义默认的实现方法
3、接口可以继承多个接口:extends xxx,xxx
public interface Weapon2 extends Weapon,Weapon1{
//接口可以继承接口,可以继承多个接口
}

一个具体类实现接口使用implements关键字,一个类只能有一个父类,但是可以实现多个接口
class Hero implements Weapon,Weapon2{
//一个类只能继承一个父类,但是可以实现多个接口
//使用implements关键字,以逗号隔开。
//非抽象类实现接口必须重写接口中的抽象方法
	@Override
	public void kill() {
		// TODO Auto-generated method stub
		
	}	
}

5、抽象类实现接口可以不实现接口的方法,因为二者都是抽象的
6、在接口中定义的方法没有声明 访问修饰符,默认为public
7、接口不能有构造方法
8、接口不能被实例化,不能new 接口

14instanceof关键字的作用

instanceof是Java的一个二元操作符(运算符),也是Java的保留关键字。它的作用是判断其左边对象是否为其右边类的实例,返回的是boolean类型的数据。用它来判断某个对象是否是某个Class类的实例。

使用方法:object instanceof class

object :必选项。任意引用对象。

class:必选项。任意已定义的对象类。

说明:如果该object 是该class的一个实例,那么返回true。如果该object 不是该class的一个实例,或者object是null,则返回false。

15抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类就是抽象类。abstract class

抽象类往往用来对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。

抽象类具有以下特性:

抽象类不能实例化。
抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类

public abstract class People {
	//由abstract修饰符修饰的类就是抽象类
	abstract void work();
	//由abstract修饰符修饰的方法就是抽象方法,没有具体的方法执行,即方法体{}
}
class Doctor extends People{
// 非抽象的子类继承抽象父类,必须重写父类中的抽象方法
	@Override
	void work() {//子类重写的方法必须有方法执行体{}
		System.out.println("救死扶伤");
	}
	
}

不能用 final修饰符修饰抽象类,因为这两个修饰符的含义是相反的。 采用 final修饰符的类无法继承,而 abstract 修饰符要求对类进行继承。
从抽象类派生的非抽象类必须包括继承的所有抽象方法,并且实际的实现该父类中的抽象方法。
抽象类不能直接实例化,并且对抽象类使用 new 运算符会导致编译时错误。虽然一些变量和值在编译时的类型可以是抽象的,但是这样的变量和值必须或者为 null,或者含有对非抽象类的实例的引用(此非抽象类是从抽象类派生的)。

public static void main(String[] args) {
		//People p1 =new People();//编译错误,抽象类不能实例化
		People p2 = new Doctor();//编译正确
	}

在面向对象方法中,抽象类主要用来进行类型隐藏。构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现,则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。

异常体系

img

Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。异常和错误的区别是:异常能被程序本身可以处理,错误是无法处理。

在 Java 应用程序中,异常处理机制为:抛出异常,捕捉异常。

1、使用 throw ,throws关键字抛出异常

一个方法不处理这个异常,而是调用层次向上传递,谁调用这个方法,这个异常就由谁来处理。

1.1、throws
将throws关键声明在可能出现异常的方法声明处,就能够将将来程序运行时出现的异常,抛给”上一级“ ,提醒该方法的调用者来处理异常 。所谓上一级就是调用这个出现了异常的方法的调用者,调用者同样需要对这个抛上来的异常进行处理,它的处理方式也有两种。

注意:若是Java中的异常发生之后一直往上抛,且抛的过程中不能解决这个异常,最终抛给了main方法,main方法抛给jvm,jvm知道异常发生后就会终止程序的运行

修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2 ... { }

1.2throw

throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。

throw new 异常类名(参数);

2、使用try catch 方式捕捉异常

关键词try后的一对大括号将一块可能发生异常的代码包起来,称为监控区域。Java方法在运行过程中出现异常,则创建异常对象。将异常抛出监控区域之 外,由Java运行时系统试图寻找匹配的catch子句以捕获异常。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。

匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。

使用格式:

try {
   ...  //监视代码执行过程,一旦返现异常则直接跳转至catch,
        // 如果没有异常则直接跳转至finally
} catch (SomeException e) {
    ... //可选执行的代码块,如果没有任何异常发生则不会执行;
        //如果发现异常则进行处理或向上抛出。
} finally {
    ... //必选执行的代码块,不管是否有异常发生,
        // 即使发生内存溢出异常也会执行,通常用于处理善后清理工作。
}

线程

多线程实现的方式

第一种方式:

编写一个类,直接 继承 java.lang.Thread重写 run方法

  1. 怎么创建线程对象? new继承线程的类。
  2. 怎么启动线程呢? 调用线程对象的 start() 方法。
public class ThreadTest02 {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        // 启动线程
        //t.run(); // 不会启动线程,不会分配新的分支栈。(这种方式就是单线程。)
        t.start();
        // 这里的代码还是运行在主线程中。
        for(int i = 0; i < 1000; i++){
            System.out.println("主线程--->" + i);
        }
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        // 编写程序,这段程序运行在分支线程中(分支栈)。
        for(int i = 0; i < 1000; i++){
            System.out.println("分支线程--->" + i);
        }
    }
}

t.run() 不会启动线程,只是普通的调用方法而已。不会分配新的分支栈。(这种方式就是单线程。)

t.start() 方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成之后,瞬间就结束了。
这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开出来,start()方法就结束了。线程就启动成功了。
启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)。
run方法在分支栈的栈底部,main方法在主栈的栈底部。run和main是平级的。

第二种方式

编写一个类,实现 java.lang.Runnable 接口,实现**run方法**。

  1. 怎么创建线程对象? new线程类传入可运行的类/接口。

  2. 怎么启动线程呢? 调用线程对象的 start() 方法。

    public class ThreadTest03 {
        public static void main(String[] args) {
            Thread t = new Thread(new MyRunnable()); 
            // 启动线程
            t.start();
            
            for(int i = 0; i < 100; i++){
                System.out.println("主线程--->" + i);
            }
        }
    }
    
    // 这并不是一个线程类,是一个可运行的类。它还不是一个线程。
    class MyRunnable implements Runnable {
        @Override
        public void run() {
            for(int i = 0; i < 100; i++){
                System.out.println("分支线程--->" + i);
            }
        }
    }
    
    

    第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,更灵活

    实现Runnable接口比继承Thread类所具有的优势:

    1):适合多个相同的程序代码的线程去处理同一个资源

    2):可以避免java中的单继承的限制

    3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

    4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

零碎知识点

静态方法:Thread.sleep(1000);
参数是毫秒
作用: 让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其它线程使用。
这行代码出现在A线程中,A线程就会进入休眠。
这行代码出现在B线程中,B线程就会进入休眠。
Thread.sleep()方法,可以做到这种效果:
间隔特定的时间,去执行一段特定的代码,每隔多久执行一次。

 sleep(): 强迫一个线程睡眠N毫秒。 
  currentThread(): 得到当前线程。 
  setName(): 为线程设置一个名称。
  wait(): 强迫一个线程等待。 
  notify(): 通知一个线程继续运行。 
  setPriority(): 设置一个线程的优先级。

线程安全

synchronized-线程同步

synchronized(){
	// 线程同步代码块。
}
synchronized后面小括号() 中传的这个“数据”是相当关键的。这个数据必须是 多线程共享 的数据。才能达到多线程排队。

集合类

基本框架

img

集合分为单列集合和双列集合

考点一:ArrayList 集合底层是数组,LinkedList集合底层是数组,ArrayList查询的效率高,LinkedList插入和删除效率高。

知识点

List:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。
Set:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。

Map是一个键值对集合,存储键、值和之间的映射。 Key无序,唯一;value 不要求有序,允许重复。Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。

单列集合的遍历方式

  public static void main(String[] args) {
        Collection<String> list=new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        Iterator<String> it =list.iterator();

        while (it.hasNext()){
            String s=it.next();
            System.out.println(s);
        }
        //stream流结合lamada表达式。遍历集合
        list.stream().forEach(s-> System.out.println(s)); 
        for (String s:list){
            System.out.println(s);
        }
    }

map集合遍历的方式

   public static void main(String[] args) {
        Map<Integer,String> map =new HashMap<>();
        map.put(1,"1");
        map.put(2,"2");
        //比较繁琐的方法,先获取键,通过键获取只
        for(Integer I:map.keySet()){
            System.out.println(I+" "+ map.get(I));
        }
    }
      public static void main(String[] args) {
        Map<Integer,String> map =new HashMap<>();

        for (Map.Entry<Integer,String> entry:map.entrySet()){
            System.out.println(entry.getKey()+"  "+ entry.getValue());
        }
    }
    public static void main(String[] args) {
        Map<Integer,String> map =new HashMap<>();

        Iterator<Map.Entry<Integer,String>> it=map.entrySet().iterator();

        while (it.hasNext()){
            Map.Entry<Integer,String> entry =it.next();
            System.out.println(entry.getKey()+" " +entry.getValue()) ;
        }
    }

接口比较

comparable和comparator接口

public class able {

    public static void main(String[] args) {
        List<Student> list =new ArrayList<>();
        Student student1 =new Student(2022,"阿里",18);
        Student student2 =new Student(2022,"腾旭",56);
        Student student3 =new Student(2022,"字节",20);
        list.add(student1);
        list.add(student2);list.add(student3);

//        Collections.sort(list);


// comparator接口进行比较
        Collections.sort(list, (Student o1, Student o2) -> {
            return o1.getAge() - o2.getAge();
        });
//       Collections.sort(list, new Comparator<Student>() {
//           @Override
//           public int compare(Student o1, Student o2) {
//               return o1.getAge() - o2.getAge();
//           }
//       });
        System.out.println(list);
    }
}
public class comatorAge implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge()-o2.getAge();
    }
}

public class Student implements Comparable<Student>{
    private  int id;
    private  String name;
    private  int age;

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public int compareTo(Student o) {

      return   -this.name.compareTo(o.name); // 前面的首字母小,后面大返回的是负数,倒叙
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

考题

字符串统计不同字母出现的次数
  public static void main(String[] args) {
        //字符串统计不同字串出现的次数 使用map集合
        System.out.println("请输入一行字符串");
        Scanner sc =new Scanner(System.in);
        String s =sc.next();
        Map<Character,Integer> map =new HashMap<>();

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);

            if (map.get(c)!=null){
                int value=map.get(c);
                map.put(c,value+1);
            }else {
                map.put(c,1);
            }
        }
        //遍历map集合了
        Set<Map.Entry<Character, Integer>> entries = map.entrySet();
        for (Map.Entry<Character, Integer> map1 :entries){
            System.out.println(map1.getKey()+"出现了"+map1.getValue()+"次");
        }
    }

数组和字符串

数组知识点

数组类型本身也是类,即使是基本类型的数组也是以对象形式存在的,并不是基本数据类型

int[]array = new int[10]; //创建数组时需要指定长度

特点

  • 数组是相同数据类型元素的集合
  • 数组中的各元素有先后顺序,它们在内存中按这个先后顺序连续存放
  • 数组元素用数组的名字和它自己在数组中的顺序位置来表示
  • 数组的长度一旦确定,就不能修改

数组的遍历

public class 数组遍历和排序 {
    public static void main(String[] args) {
        int [] arr ={2,4,5,6,1,3};
        //遍历1for循环
        for (int i = 0; i <arr.length; i++) {
            System.out.print(arr[i]);
        }
        //增强for循环
        for(int n:arr){
            System.out.print(n);
        }
        //stream流 jdk8的特性
        Arrays.stream(arr).forEach(s-> System.out.println(s));
     //直接打印
        System.out.println(Arrays.toString(arr));
        //排序  调用api
        Arrays.sort(arr);

        System.out.println(Arrays.toString(arr));
    }
}

字符串

字符串中的字符一旦确定,无法进行修改,只能重新创造,字符串类是由final修饰的,不能被继承,也无法改变。

Sting类中提供了一些静态方法,常用的如下
lenth 获取长度
charAt(int index) 返回指定字符串的长度,哈希表算法经常用到
substring 截取字符串
equals()比较字符串内容是否相等
split 字符串进行分割

比较字符串的大小采用CompareTo()方法
若调用方法的字符串比较参数字符串大,返回正整数;

考题

每个用双引号括起来的字符串都是String类型的一个实例对象


    public static void main(String[] args) {
        String str = new String("Hello World!"); 
        String str3 = new String("Hello World!");
        String str1 = "Hello World!"; 
        String str2 = "Hello World!";
        System.out.println(str1 == str2); //直接创造,那么为了优化效率,则始终是同一个对象
        System.out.println(str == str3); //主动使用new,则是两个对象
        System.out.println(str.equals(str3));
    }
true
false
true

IO流

1.1 IO流分类

IO流主要的分类方式有以下3种:

  1. 按数据流的方向:输入流、输出流
  2. 按处理数据单位:字节流、字符流
  3. 按功能:节点流、处理流

IO流的作用

用来处理设备间数据传输问题
常见的应用:文件复制、文件上传、文件下载

使用场景

 如果操作的是纯文本文件,优先使用字符流

     如果操作的是二进制文件,优先使用字节流

     如果不确定,则优先使用字节流


1.2字节流

img

InputStream:字节输入流的所有类的超类 OutputStream:字节输出流的所有类的超类

1.3缓冲流

字节缓冲流
BufferedOutputStream
BufferedInputStream
 创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
 public class BufferStreamDemo {
    public static void main(String[] args) throws IOException {
        //字节缓冲输出流:BufferedOutputStream(OutputStream out)
        BufferedOutputStream bos = new BufferedOutputStream(new 				                                       FileOutputStream("myByteStream\\bos.txt"));
        //写数据
        bos.write("hello\r\n".getBytes());
        bos.write("world\r\n".getBytes());
        //释放资源
        bos.close();
        //字节缓冲输入流:BufferedInputStream(InputStream in)
        BufferedInputStream bis = new BufferedInputStream(new                                                          FileInputStream("myByteStream\\bos.txt"));
 
        //一次读取一个字节数据
//        int by;
//        while ((by=bis.read())!=-1) {
//            System.out.print((char)by);
//        }
        //一次读取一个字节数组数据
        byte[] bys = new byte[1024];
        int len;
        while ((len=bis.read(bys))!=-1) {
            System.out.print(new String(bys,0,len));
        }
 
        //释放资源
        bis.close();
    }
}
BufferedWriter  BufferedReader
字符缓冲流
public class BufferedStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //BufferedWriter(Writer out)
        BufferedWriter bw = new BufferedWriter(new                                                            FileWriter("myCharStream\\bw.txt"));
        bw.write("hello\r\n");
        bw.write("world\r\n");
        bw.close();
 
        //BufferedReader(Reader in)
        BufferedReader br = new BufferedReader(new                                                           FileReader("myCharStream\\bw.txt"));
 
        //一次读取一个字符数据
//        int ch;
//        while ((ch=br.read())!=-1) {
//            System.out.print((char)ch);
//        }
 
        //一次读取一个字符数组数据
        char[] chs = new char[1024];
        int len;
        while ((len=br.read(chs))!=-1) {
            System.out.print(new String(chs,0,len));
        }
 
        br.close();
    }
}

字符缓冲流特有功能
String readLine()读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null

1.4字符流

由于字节流操作中文不是特别的方便,所以Java就提供字符流

img

1.5序列化和反序列化

对象序列化流
对象序列化流( ObjectOutputStream):

将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象 。

构造方法:

ObjectOutputStream(OutputStream out)
创建一个写入指定的OutputStream的ObjectOutputStream。

序列化对象的方法:

void writeObject(Object obj)
将指定的对象写入ObjectOutputStream。

对象反序列化流
对象反序列化流(ObjectInputStream):

反序列化先前使用ObjectOutputStream编写的原始数据和对象。

构造方法:

ObjectInputStream(InputStream in)

创建从指定的InputStream读取的ObjectInputStream

反序列化对象的方法:

Object readObject()

从ObjectInputStream读取一个对象

1.6老师的习题

拷贝文件

public class copy实现文件的复制 {
    public static void main(String[] args) throws IOException {
        String  filename1="src/期末复习/io流/a.txt";
        String  filename2="src/期末复习/io流/b.txt";
   copy(filename1,filename2);
    }
    public static void  copy(String filename1,String filename2) throws IOException {
        //通过字节流读取
        InputStream is =null;
        OutputStream os=null;
        try {
            is=new FileInputStream(filename1);//输入流,读取文件,输入输出相对于控制台来说的

            os =new FileOutputStream(filename2);//输出流

            byte[] bytes=new byte[1024]; //创建缓冲区的字节数组

            int count=0;
            while (( count=is.read(bytes))!=-1){

                os.write(bytes,0,count);//优化
            }

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象 。

构造方法:

ObjectOutputStream(OutputStream out)
创建一个写入指定的OutputStream的ObjectOutputStream。

序列化对象的方法:

void writeObject(Object obj)
将指定的对象写入ObjectOutputStream。

对象反序列化流
对象反序列化流(ObjectInputStream):

反序列化先前使用ObjectOutputStream编写的原始数据和对象。

构造方法:

ObjectInputStream(InputStream in)

创建从指定的InputStream读取的ObjectInputStream

反序列化对象的方法:

Object readObject()

从ObjectInputStream读取一个对象

1.6老师的习题

拷贝文件

public class copy实现文件的复制 {
    public static void main(String[] args) throws IOException {
        String  filename1="src/期末复习/io流/a.txt";
        String  filename2="src/期末复习/io流/b.txt";
   copy(filename1,filename2);
    }
    public static void  copy(String filename1,String filename2) throws IOException {
        //通过字节流读取
        InputStream is =null;
        OutputStream os=null;
        try {
            is=new FileInputStream(filename1);//输入流,读取文件,输入输出相对于控制台来说的

            os =new FileOutputStream(filename2);//输出流

            byte[] bytes=new byte[1024]; //创建缓冲区的字节数组

            int count=0;
            while (( count=is.read(bytes))!=-1){

                os.write(bytes,0,count);//优化
            }

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Java 期末复习资料包括以下几个方面: 1. Java基础知识:掌握Java的基本语法、数据类型、运算符、流程控制语句等。 2. 面向对象编程:掌握Java的面向对象编程思想、类与对象、封装、继承、多态、抽象类和接口等。 3. 异常处理:掌握Java中的异常处理机制,包括异常类的层次结构、异常处理语句(try-catch-finally)、throw和throws关键字等。 4. 集合框架:掌握Java中的集合框架,包括List、Set、Map等集合容器,以及它们的特点和使用方法。 5. IO流:掌握Java中的IO流,包括字节流和字符流,文件操作等。 6. 多线程编程:掌握Java中的多线程编程,包括线程的创建和启动、线程同步、线程间通信等。 7. 数据库编程:掌握Java中的数据库编程,包括JDBC API的使用、连接数据库、执行SQL语句等。 以下是一些Java期末复习资料的推荐: 1. 《Head First Java》:这是一本非常适合初学者入门的Java书籍,内容浅显易懂,同时又不失深度,适合用来巩固Java基础知识。 2. 《Java核心技术》:这是一本全面深入的Java教材,可以帮助你系统地学习Java的各种知识点,适合用来提高Java技能水平。 3. 《Java编程思想》:这是一本讲述Java编程思想和技巧的经典书籍,涵盖了Java的基础知识、面向对象编程、异常处理、集合框架、IO流、多线程编程和数据库编程等方面的内容。 4. MOOC网站上的Java课程:例如中国大学MOOC网站上的《Java程序设计》和Coursera网站上的《Java程序设计与软件工程专项课程》,这些课程都提供了免费的在线学习资源和相关练习。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渴求sspOffer的小周同学

您的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值