期末Java面向对象程序设计复习稳过不挂指南(更新中)

目录

img

第三章.java类基础知识

第四节.自定义函数

·同一个类中,函数名称可以相同,即重载函数(overload),但函数参数的个数或者类型必须不同

第四章.面向对象和类

第一节.面向对象思想

·对象 = 属性 + 方法

·变量定义的变迁 :基本类型(一种变量) -> 结构体 (多种变量捆绑) -> 类(多种变量 + 方法)

·子类天然继承父类的所有东西,除了父类的private(私有)变量

·子类必须通过父类的方法才能访问父类的私有变量

public class Father {
	private int money  = 100; //私有
	long mobile = 139999L;
	
	public void hello() {
		System.out.println("Hello\n");
	}
}

public class Son extends Father{
	public void hi () {
		System.out.println("hi~~~");
	}
	
	public static void main(String[] args) {
		Son s = new Son();
//		System.out.println(s.money);  //error 父类的money是私有的,子类无法直接访问
		System.out.println(s.mobile); //Son没有定义mobile,而是通过父类继承
		s.hello(); //Son没有定义f1,而是通过父类继承的
		s.hi();	//子类可以自定义自己的成员方法
	}
}

第二节.java类和对象

A obj1 = new A();

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

·在c/c++中, obj1 被称为指针, 在java中称为 Reference

public class Mynumber {
	int num = 5;
}

public class ArgumentPassingTest {
	public static void main(String[] a) {
		int a = 1, b = 2;
		swap(a, b);
		System.out.println("a is " + a + ", b is " + b); // a = 1 , b = 2
		
		Mynumber obj1 = new Mynumber();
		Mynumber obj2 = new Mynumber();
		
		obj2.num = 10;
		swap(obj1, obj2);
		System.out.println("obj1 is " + obj1.num + ", obj2 is " + obj2.num);
	}
	
	public static void swap(int m, int n) {
//而基本类型是直接值拷贝
		int t = m; 
		m = n;
		n = t;
	}
	
	public static void swap(Mynumber obj3, Mynumber obj4) {
//因为对象是比较庞大的,所以它的赋值是直接赋指针的,所以obj3和obj1实际上指向的是同一块内存!
//对象赋值是Reference赋值(赋值采用共享同一块内存区域)
		int t = obj3.num;
		obj3.num = obj4.num;
		obj4.num = t;
	}
}

第三节.构造函数

·变量存活周期:离它最近的大括号之中

·JVM特有GC机制,所以java不需要析构函数回收对象

·每个子类的构造函数第一行都默认调用父类的无参数构造函数super()

第四节.信息隐藏和this

·面向对象有一个法则:信息隐藏

··类的成员属性private私有的

··类的方法public公开的,通过方法修改成员属性的值

··通过类的方法来间接访问类的属性,而不是直接访问类的属性

class InfoHiding {
	private int id;
	
	public InfoHiding(int id2) {
		id = id2;
	}
	
	public void setId (int id2) {
		id = id2;
	}
	
	public int getId() {
		return id;
	}
}
public class InfoHidingTest {
	public static void main(String[] args) {
		InfoHiding obj = new InfoHiding(10);
		obj.setId(20);
		System.out.println(obj.getId());
	}
}

·this负责指向本类中的成员变量

·this负责指向本类中的成员方法

·this可以代替本类的构造函数

public class ThisTest {
	public static void main(String[] args) {
		MyPairNumber obj = new MyPairNumber(5);
		System.out.println(obj.sum());
	}
}

public class MyPairNumber {
	private int m, n;

	public int getM() {
		return m;
	}

	public void setM(int m) {
		this.m = m;
	}

	public int getN() {
		return n;
	}

	public void setN(int n) {
		this.n = n;
	}
	
	public MyPairNumber() {
		this(0 ,0);
	}
	
	public MyPairNumber(int m) {
		this(m, 0);
	}
	
	public MyPairNumber(int m, int n) {
		this.m = m;
		this.n = n;
	}
	
	public int sum () {
		return this.add(m, n);
	}
	
	public int add(int a, int b) {
		return a + b;
	}
}

第五章.继承,接口 和 抽象类

第一节.继承

·子类继承父类的所有属性和方法(但不能直接访问private成员)

·根据信息隐藏原则,子类继承父类的所有方法,所以可以直接使用

·子类也会继承父类的父类的属性和方法(但不能。。

·在同样方法名和参数的情况下,本类的方法比父类的方法优先级

public class Base {
	private int num = 10;
	
	public int getNum() {
		return num;
	}
}

public class Derived extends Base{
	private int num = 20;
	
	public int getNum() {
		return this.num;
	}
	
	public static void main(String[] args) {
		Derived foo = new Derived();
		System.out.println(foo.getNum()); //20
	}
}

·单根继承原则(与c++不同

·如果不写extends,java类都默认继承 java.lang.Object类

public class A {
	public A () {
		System.out.println("11111");
	}
	public A (int a) {
		System.out.println("22222");
	}
}

public class B extends A{
	public B () {
		System.out.println("33333");
	}
	public B (int a) {
		System.out.println("44444");
	}
	
	public static void main(String[] args) {
		B obj1 = new B();
		System.out.println("=====");
		B obj2 = new B(10);
	}
}

11111
33333
=====
11111
44444

但如果

public class B extends A{
	public B () {
		super();
		System.out.println("33333");
	}
	public B (int a) {
		super(a);
		System.out.println("44444");
	}
	
	public static void main(String[] args) {
		B obj1 = new B();
		System.out.println("=====");
		B obj2 = new B(10);
	}
}

11111
33333
=====
22222
44444

第二节.抽象类和接口

抽象类

·一个完整的类(所有方法都有实现)才可以被实体化,才可以被new出来

public abstract class Shape {
	int area;
	public abstract void calArea();
}
public class Rectangle extends Shape{
	
	int width;
	int length;
	
	public Rectangle (int length, int width) {
		this.length = length;
		this.width = width;
	}
	
	public void calArea () {
		System.out.println(this.length * this.width);
	}
	
	public static void main(String[] args) {
		Rectangle rect = new Rectangle (5, 10);
		rect.calArea();
	}
}

接口

·如果类的所有方法都没有实现,那么这个类就算是接口interface

public interface Animal {
	public void eat();
	public void move();
}

·类只可以继承extends一个类,但是可以实现implements多个接口,继承和实现可以同时

·继承抽象类,必须实现所有abstract的方法;实现多个接口,必须实现接口中所定义的所有方法

·接口不算类,或者说是特殊的类

·接口可以继承(多个)接口,没有实现的方法将会叠加

·接口里可以定义变量,但一般是常量

public interface ClimbTree {
	public void climb();
}

public abstract class LandAnimal implements Animal {
	public abstract void eat();
    
	public void move() {
		System.out.println("I can move by feet");
	}
}

·extends 必须写在 inplements 的前面

public class Rabbit extends LandAnimal implements ClimbTree {
	//继承一个抽象类,实现一个接口,都要实现abstract方法
	public void eat() {
		System.out.println("Rabbit : I can eat");
	}
	
	public void climb() {
		System.out.println("Rabbit : I can climb");
	}
}

public interface CatFamily extends Animal, ClimbTree{
	//CatFamily接口继承于两个接口,相当于将多个接口中未实现的方法都“承载”过来
	
	//eat()
	//move()
	//climb()
}

public class Tiger implements CatFamily{
	
	public void eat() {
		System.out.println("eat");
	}
	
	public void move() {
		System.out.println("move");
	}
	
	public void climb() {
		System.out.println("climb");
	}
}

·抽象类和接口共同点: 两者都不能被实例化,不能new操作

·抽象类和接口不同点

··抽象类abstract, 接口interface

··抽象类可以有部分方法实现,接口所有方法都不能有实现

··一个类只能继承一个(抽象)类,但可以实现多个接口

··接口可以继承extends多个接口

··抽象类可以有构造函数,接口没有构造函数

··抽象类可以有main,也能运行,接口没有main函数

··抽象类方法可以有private/protected,接口方法都是public

第三节.转型,多态和契约设计

类转型

·变量(基本类型变量)支持互相转化,比如 int a = (int)3.5; // a = 3(把小数部分截断)

·类型可以相互转型,但是只限制于有继承关系的类

··子类可以转换成父类(接口也算父类)(从大变小,即向上转型),但父类不能转换成子类

	Human obj1 = new Man(); //OK, Man extends Human
	Man obj2 = new Human(); //illegal

·父类转为子类有一种情况例外

··就是这个父类本身就是从子类转化过来的

	Human obj1 = new Man();
	Man obj2 = (Man) obj1; //OK,obj1 is born from Man class

多态

·类型转换,带来的作用就是多态

·子类继承父类的所有方法,但子类可以重新定义一个名字,参数和父类一样的方法,这种行为就是重写(覆写,覆盖,overwrite/override, not overload(重载))。重写是指子类的方法替换掉父类的方法

·而重载overload是值函数名一样,形参不一样,是指两个不同的方法

·子类的方法的优先级是高于父类的

public class Man extends Human{
	
	public void eat() {
		System.out.println("I can eat more!!!");
	}
	
	public void plough() { }
	
	public static void main(String[] args) {
		Man obj1 = new Man();
		obj1.eat(); //call Man.eat()
		Human obj2 = (Human) obj1;
		//obj2转型前是obj1,而obj1是Man类型,所以obj2本质上是Man类型
		obj2.eat(); // call Man.eat()
		Man obj3 = (Man) obj2;
		//obj2本身也是脱胎于obj1,由于obj3是一个Man对象
		obj3.eat(); // call Man.eat()
	}
}

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

·obj2相当于是拿了块布把obj1多余的部分盖起来了,obj3把这块布又掀开了,然后再指向obj3

	obj1 == obj2; //true
	obj2 == obj3; //true
	//意味着这三个东西都指向同一块内存(不要忘了它们是reference,值代表指向的内存)

·多态的两个作用

··多态:可以以统一的接口来操纵某一类中不同的对象的动态行为

··多态:对象之间的解耦(只要送进去一个实现了Animal接口的对象(Cat,Dog,new,匿名类

public interface Animal {
	public void eat();
	public void move();
}

public class Cat implements Animal{
	
	public void eat() {
		System.out.println("Cat : eat");
	}
	
	public void move() {
		System.out.println("Cat : move");
	}
}

public class Dog implements Animal{
	
	public void eat() {
		System.out.println("Dog : eat");
	}
	
	public void move() {
		System.out.println("Dog : move");
	}
}

public class AnimalTest {

	public static void main(String[] args) {
		Animal[] as = new Animal[4];
		as[0] = new Cat(); //隐性地做了转型操作,因为Cat继承于Animal,实现了它这个接口,子类可以转型成父类
		as[1] = new Dog();
		as[2] = new Cat();
		as[3] = new Dog();
		
		for (int i = 0; i < as.length; i ++ ) {
			as[i].move(); //调用每个元素自身的move方法
		}
		
		for (int i = 0; i < as.length; i ++ ) {
			//这个方法前不需要写类名 
			haveLunch(as[i]);
			//haveLunch的形参是Animal对象,而as这个数组也是Animal对象
			//而eat调的肯定不是Animal的方法,而是每个元素自身的eat
		}
		
		haveLunch(new Cat()); //隐性转型 Animal a = new Cat(); haveLunch(a);
		haveLunch(new Dog());
		//Animal是个接口,不可以new的,但在这里可以new出来,条件是
		//把它eat方法和move方法给补全,就可以产生一个匿名的类
		//这个类,没有名字但是可以产生出这样一个对象,反正这个类只要用一次
		//28到38行算一句话,隐藏地new了一个Animal的子类
        
        //只需要传进去一个实现Animal接口的对象,就可以运行haveLunch方法
		haveLunch(
						new Animal()
						{
							public void eat() {
								System.out.println("Anonymous : eat");
							}
							
							public void move() {
								System.out.println("Anonymous : move");
							}
						});
	}
	
	public static void haveLunch(Animal a) {
		a.eat();
	}
}

契约设计

总结

类转型:

子类可以转父类,父类不可以转子类(除非父类对象本身就是子类)

多态:

子类转型成父类后,调用普通方法,依旧是子类的方法

契约设计:

类不会直接使用另外一个类,而是采用接口的形式,外部可以“空投“这个接口下的任意子类对象

第六章.static, final 和 常量设计

第一节.static

静态变量, 类共有成员

public class Potato {
	static int price = 5;
	String content = "";
	public Potato (int price, String content) {
		this.price = price;
		this.content = content;
	}
	public static void main(String[] a) {
		System.out.println(Potato.price); //5			//Potato.contend -> wrong
		System.out.println("===========");
		Potato obj1 = new Potato(10, "青椒土豆丝");
		System.out.println(Potato.price); //10
		System.out.println(obj1.price); //10
		//Potato.price和obj1.price在内存中是同一个东西
		//也就是说,在内存中只有一个price,这个price既可以通过Potato.price,也可以通过obj1.price
		
		System.out.println("============");
		Potato obj2 = new Potato(20, "酸辣土豆丝");
		System.out.println(Potato.price); //20
		System.out.println(obj2.price); //20
	}
}

·static变量只依赖于类存在(通过类即可访问),不依赖于对象实例存在。即可以通过Potato.price即可访问

·所有的对象实例,如obj1和obj2关于price变量的值都共享存储在一个共同的空间(栈)

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

static方法

·静态方法也无需通过对象来引用,而通过类名直接就可以引用

·在静态方法中,只能使用静态变量,不能使用非静态变量

·静态方法禁止引用非静态方法,非静态方法可以调用静态方法

public class StaticMethodTest {
	int a = 11111;
	static int b = 22222;
	
	public static void hello() {
		System.out.println(b);
		//System.out.println(a); //error
		//hi(); //error
	}
	
	public void hi() {
		hello();  //ok
		System.out.println(a); //ok
		System.out.println(b); //ok
	}
	
	public static void main(String[] a) {
		StaticMethodTest.hello(); 
		//StaticMethodTest.hi(); //errod
		StaticMethodTest foo = new StaticMethodTest();
		foo.hello(); //warning, but ok
		foo.hi();
	}
}

static修饰类(内部类)

static块

·只在类第一次被加载时调用

·换句话说,在程序运行期间,这段代码只运行一次

·执行顺序:static块 > 匿名块 > 构造函数

class StaticBlock {
	//类中不仅有成员方法和成员变量,还有代码块
	//static block > anonymous  block > constructor function
	
	//加了个static的代码块,叫静态代码块
	static
	{
		System.out.println("22222222");
	}
	
	//12-14是匿名代码块,可以认为是一个没有名字的函数
	{
		System.out.println("11111111");
	}
	
	public StaticBlock()
	{
		System.out.println("33333333");
	}
	
	{
		System.out.println("44444444");
	}
}
public class StaticBlockTest {
	public static void main(String[ ] a) {
		System.out.println("00000000");
		// TODO Auto-generated method stub
		StaticBlock obj1 = new StaticBlock();
		StaticBlock obj2 = new StaticBlock();
	}
}
00000000
22222222
11111111
44444444
33333333
11111111
44444444
33333333

第二节.单例模式/单态模式

·单例模式:保证一个类有且只有一个对象

··采用static来共享对象实例

··采用private构造函数,防止外界new操作

public class Singleton {
	//Singleton这个只会被new一次
	private static Singleton obj = new Singleton(); //定义一个静态变量,共享同一个对象
	private String content;
	
	private Singleton() //确保只能在类内部调用构造函数,防止外界new
	{
		this.content = "abc";
	}
	
	public String getContent()
	{
		return content;
	}
	
	public void setContent(String content)
	{
		this.content = content;
	}
	
	//不管在外界调用多少次getInstance()方法,所拿到的对象实例都是obj
	public static Singleton getInstance()
	{
		//静态方法使用静态变量
		//另外可以使用方法内的临时变量,但是不能引用非静态的成员变量
		return obj;
	}
	
	public static void main(String[] a) {
		Singleton obj1 = Singleton.getInstance();
		System.out.println(obj1.getContent()); //abc
		
		Singleton obj2 = Singleton.getInstance();
		System.out.println(obj2.getContent());  //abc
		
		obj2.setContent("def");
		System.out.println(obj1.getContent()); //def
		System.out.println(obj2.getContent()); //def
		
		System.out.println(obj1 == obj2); //true,obj1和obj2指向同一个对象
	}
}

第三节.final

final类

·final的类不能被继承

	final public class FinalFather{}

final方法

·父类中如果有final方法,子类中不能改写这个方法,不过在f1中加些参数就可以了,因为这不是重写是重载

	public final void f1(){}

final变量

·不能再次赋值

··如果是基本型别的变量,不能修改其值,

··如果是对象实例,那么不能修改其指针(但是可以修改对象内部的值)

class FinalObject
{
	int a = 10;
}
public class FinalObjectTest {
	
	public static void main(String[] args) {
		final FinalObject obj1 = new FinalObject();
		System.out.println(obj1.a);
		obj1.a = 20;
		System.out.println(obj1.a); //20
		
		//obj1 = new FinalObject(); //error
	}
}

第四节.常量设计和常量池

常量

·常量是不会被修改的,在内存空间中,只需要保留一份,只读

·一种不会修改的变量

·不能修改 final

·不会修改、只读、只要一份 static

·方便访问 public

·public static final

·建议变量名字全大写,以连字符相连,如UPPER_BOUND(和驼峰命名不一样,示例:mySalary,userCount

·如果变量是static且final的,static保证只有一份,final保证值不会被修改,那么这个变量就是常量

public class Constants {
	public static final double PI_NUMBER = 3.14;
	public final static String DEFAULT_COUNTRY = "China";
	
	public static void main(String[] a) {
		System.out.println(Constants.PI_NUMBER);
		System.out.println(Constants.DEFAULT_COUNTRY);
	}
}

一种特殊的常量

接口内定义的变量默认是常量

public interface SpecialAnimal {
	String color = "yellow"; //default : public static final
	public void move();
}
public class Cat implements SpecialAnimal{
	public void move() 
	{
		System.out.println("I can move");
	}
	
	public static void main(String[] a){
		Cat cat = new Cat();
		cat.color = "white"; //error
	}
}

常量池

public class IntegerTest {
	public static  void main(String[] a){
		Integer n1 = 127;
		Integer n2 = 127;
		System.out.println(n1 == n2); //true
		Integer n3 = 128; 
		Integer n4 = 128;
		System.out.println(n3 == n4); //false
        //虽然Integer包装类范围和int一样,但是-128~127才有常量池,所以false
		Integer n5 = new Integer(127);
		System.out.println(n1 == n5); //false
	}
}

常量池:相同的值只存储一份,节省内存,共享访问

·java为很多基本类型的包装类/字符串都建立常量池

·基本类型的包装类:(前面六个有(缓存)常量池)

Boolean, Byte, Short, Integer, Long, Character, Float, Double

​ ·Boolean : true, false

​ ·Byte : -128 ~ 127 ,Character : 0 ~ 127

​ ·Short, Int, Long : -128 ~ 127

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

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

public class CacheTest {
	
	public static void main(String[] args) {
		Boolean b1 = true; //基本类型的包装类,b1是个对象
		Boolean b2 = true;
		//由于b1和b2是对象,所以 “==”是判断它们的指针是否相同
		System.out.println("Boolean Test : " + String.valueOf(b1 == b2)); //true
		
		Byte b3 = 127;
		Byte b4 = 127;
		System.out.println("Byte Test : " + String.valueOf(b3 == b4)); //
		
		Character c1 = 127;
		Character c2 = 127;
		System.out.println("Character Test : " + String.valueOf(c1 == c2));
		
		Short s1 = -128;
		Short s2 = -128;
		System.out.println("Short Test : " + String.valueOf(s1 == s2));
		
		Integer i1 = -128;
		Integer i2 = -128;
		System.out.println("Integer Test : " + String.valueOf(i1 == i2));
		
		Long l1 = -128L;
		Long l2 = -128L;
		System.out.println("Long Test : " + String.valueOf(l1 == l2));
		
		Float f1 = 0.5f;
		Float f2 = 0.5f;
		System.out.println("Float Test : " + String.valueOf(f1 == f2)); //false
		
		Double d1 = 0.5;
		Double d2 = 0.5;
		System.out.println("Doule Test : " + String.valueOf(d1 == d2)); //false
	}
}

·java为常量字符串都建立常量池缓存机制

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

public class StringConstantTest {
	public static void main(String[] a) {
		String s1 = "abc";
		String s2 = "abc";
		String s3 = "ab" + "c"; //都是常量,编译器将优化,下同
		String s4 = "a" + "b" + "c";
		System.out.println(s1 == s2); //t
		System.out.println(s1 == s3); //t
		System.out.println(s1 == s4); //t
	}
}

·基本类型的包装类和字符串有两种创建方式

··常量式(字面量)赋值创建, 放在栈内存(将被常量化)

···Integer a = 10;

···String b = “abc”;

··new对象进行创建, 放在堆内存(不会常量化)

···Integer c = new Integer(10);

···String d = new String(“abc”);

·这两种创建方式导致创建的对象存放位置不同

·栈内存读取速度快但容量小,。。(因为new会根据构造函数来创建对象,java会觉得这种对象比较庞大,所以通常放在比较大的堆内存;而那种固定的值,比较小,会常量化放在栈内存

//分析Interger类
///基本类型和包装类进行比较,将对包装类自动拆箱
///对象比较,比较地址
///加法+会自动拆箱
public class BoxClassTest {
	public static void main(String[] args){
		int i1 = 10;
		Integer i2 = 10;					//自动装箱
		System.out.println(i1 == i2); //true
		// 自动拆箱  基本类型和包装类进行比较,包装类自动拆箱,然后就变成数值比较
		
		Integer i3 = new Integer(10);
		System.out.println(i1 == i3); //true
		// 自动拆箱 	基本类型和包装类进行比较。。。
		
		System.out.println(i2 == i3); //false
		//两个对象比较,双等号比较其地址
		//i2是常量,放在栈内存常量池中,i3是new出对象,放在堆内存中
		
		Integer i4 = new Integer(5);
		Integer i5 = new Integer(5);
		System.out.println(i1 == (i4 + i5)); //true
		System.out.println(i2 == (i4 + i5)); //true
		System.out.println(i3 == (i4 + i5)); //true
		//i4 + i5操作将会使i4,i5自动拆箱为基本类型并运算得到10
		//基础类型10和对象比较,将会使对象自动拆箱,做基本类型比较
		
		Integer i6 = i4 + i5; // +操作使i4,i5自动拆箱,得到10,因此i6 == i2
		System.out.println(i1 == i6); //true
		System.out.println(i2 == i6); //true
		System.out.println(i3 == i6); //false
	}
}

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

//分析String类
///常量赋值(堆内存)和new创建(栈内存)不是同一个对象
///编译器只会优化确定的字符串,并缓存
public class StringNewTest {
	
	public static void main(String[] args){
		String s0 = "abcdef";
		String s1 = "abc";
		String s2 = "abc";
		String s3 = new String("abc");
		String s4 = new String("abc");
		System.out.println(s1 == s2); //true,常量池
		System.out.println(s1 == s3); //false 一个堆内存,一个栈内存
		System.out.println(s3 == s4); //false 两个都是堆内存
		System.out.println("==============");
		
		String s5 = s1 + "def"; //涉及到变量,故编译器不优化
		String s6 = "abc" + "def"; //都是常量,编译器会自动优化成abcdef
		String s7 = "abc" + new String("def"); //涉及到new对象,编译器不优化
		System.out.println(s5 == s6); //false
		System.out.println(s5 == s7); //false
		System.out.println(s6 == s7); //false
		System.out.println(s0 == s6); //true
		System.out.println("==============");
		
		String s8 = s3 + "def"; //不
		String s9 = s4 + "def"; //不
		String s10 = s3 + new String("def"); //不
		System.out.println(s8 == s9); //f
		System.out.println(s8 == s10); //f 
		System.out.println(s9 == s10); //f
	}
}

第五节.不可变对象和字符串

不可变对象 Immutable Object

·提高读效率

·一旦创建,这个对象(状态/值)不能被更改了

·其内在的成员变量的值就不能修改了

·e.g. 八个基本型别的包装类

·e.g. String, BigInteger, BigDecimal等

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

		String a = new String("abc");
		String b = a;
		System.out.println(b);
		//不可变对象是指值对象不再修改,即abc不会被修改,而指针(句柄/变量名)a的指向可以修改
		a = "def";
		System.out.println(b);

·不可变对象,也是传指针(引用) (只要是对象函数调用,都是传指针)

·由于不可变,临时变量指向新内存,外部实参的指针不改动

    public static void change(String b)
    {
        b = "def";
    }
    String a = "abc";
    change(a);
    System.out.println(a);

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

传指针,所以b也是指向"abc"

·如何创建不可变对象

··所有的属性都是private和final的

··不提供setter方法

··类是final的,或者所有方法都是final的

Java字符串

·字符串是Java使用最多的类,是一种典型的不可变对象

·String定义有两种:

··String a = “abc”; //常量赋值,栈分配内存

··String b = new String(“abc”); //new对象,堆分配内存

·字符串内容比较:equals方法

·是否指向同一个对象:指针比较==

·Java常量池(Constant Pool)

​ 保存在编译期间就已经确定的数据

​ 是一块特殊的内存

​ 相同的常量字符串只存储一份,节省内存,共享访问

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

·字符串的加法

​ String a = “abc”;

​ a = a + “def”; //由于String不可修改,效率差 (要先申请一个新的空间,老的还放在这,指针指向新的空间)

​ 使用StringBuffer / StringBuilder类的append方法进行修改(以abc为基础,扩张为abcdef)

​ StringBuffer/StringBuilder的对象都是可变对象

​ StringBuffer(同步,线程安全,修改快速).StringBulider(不同步,线程不安全,修改更快)

import java.util.Calendar;

public class StringAppendTest {
	
	public static void main(String[] args){
		int n = 50000;
		Calendar t1 = Calendar.getInstance();
		String a = new String();
		for (int i = 0; i < n; i ++ )
		{
			a = a + i + ",";
		}
		System.out.println(Calendar.getInstance().getTimeInMillis() - t1.getTimeInMillis());
		
		Calendar t2 = Calendar.getInstance();
		StringBuffer b = new StringBuffer("");
		for (int i = 0; i < n; i ++ )
		{
			b.append(i);
			b.append(",");
		}
		System.out.println(Calendar.getInstance().getTimeInMillis() - t2.getTimeInMillis());
		
		Calendar t3 = Calendar.getInstance();
		StringBuilder c = new StringBuilder("");
		for (int i = 0; i < n; i ++ )
		{
			c.append(i);
			c.append(",");
		}
		System.out.println(Calendar.getInstance().getTimeInMillis() - t3.getTimeInMillis());
	}
}

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

public class ArgumentPassing {
	public static void changeValue(int a)
	{
		a = 10;
	}
	
	public static void changeValue(String s1)
	{
		s1 = "def";
	}
	
	public static void changeValue(StringBuffer s1)
	{
		s1.append("def");
	}
	
	public static void main(String[] args){
		int a = 5;
		String b = "abc";
		StringBuffer c = new StringBuffer("abc");
		changeValue(a);
		changeValue(b);
		changeValue(c);
		System.out.println(a);
		System.out.println(b);
		System.out.println(c);
	}
}

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

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

第七章.package, import 和 classpath

第一节.package和import

package

·package必须和目录层次一样

·所有的Java类都放在同一个目录下,因此类之间的相互调用无需显式声明调用

​ 同一个目录下,两个类的名字不能相同

​ 文件过多,查找和修改都不易

·Java支持多个目录放置java,并且通过package, import, classpath, jar等机制配合使用,可以支持跨目录放置和调用java类

·package包,和C++中namespace类似

·在java类文件的第一句话给出包的名称

//	cn/edu/ecnu/PackageExample.java

import cn.edu.ecnu;
public class PackageExample
{}

·类全称(包名 + 类名) cn.edu.ecnu.PackageExample, 短名称PackageExample

·引用类时,必须使用类全称引用,程序正文可以使用短名称

·域名是唯一的,因此常用域名当包名

·域名逆序:cn.edu.ecnu, 范围通常由大到小 中国->教育网站->华东师大

·包名 : 和目录层次一样

·目录分隔符在windows上是\,unix和mac是/,但java用/都兼容

import

package cn.edu.ecnu;
import cn.edu.ecnu.PackageExample;
//或 import cn.edu.ecnu.*;
//但不可以 import cn.*;
//如果PackageExample和当前类在同一个目录下,可以省略上句import

public class PackageExampleTest{
	public static void main(String[] agrs){
		PackageExample obj = new PackageExample();
		//此时可用类的短名称来引用
	}
}

· * 代表这个目录下的所有文件,但不包括子文件夹和子文件夹中的所有文件,比如import java.lang.* 不包括java.lang.reflect.*

package c;

import a.Man;

public class Test{
	public static void main(String[] args){
		Man m1 = new Man();
		b.Man m2 = new b.Man(); //如何添加重名的类,写全名即可
	}
}

第四节.java访问权限

·java访问权限有四种:

private : 私有的,只能本类访问

default(通常缺省不写): 同一个包内访问

​ **protected **: 同一个包,子类均能访问

public : 公开的,所有类都能访问

·使用范围:

​ 四种都可以修饰成员变量,成员方法,构造函数

​ default和public可以修饰类

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

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

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

B:同包,非子类

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

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

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

C:同包,子类

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

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

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

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

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

D:不同包,子类

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

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

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

E:不同包,非子类

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

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

第八章.Java常用类

第一节.java类库概述

·java类库

​ 包名以java开始的包是java核心包

​ javax java拓展包

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

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

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

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

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

第二节.数字相关类

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

大数字类

大整数类BigInteger

​ 支持无限大的整数运算

大浮点数类BigDecimal

​ 支持无限大的小数运算

​ 注意精度和截断

import java.math.BigInteger;

public class BigIntegerTest {
	public static void main(String[] args){
		BigInteger b1 = new BigInteger("123456789");
		BigInteger b2 = new BigInteger("987654321");
		System.out.println("b1 : " + b1 + ", b2 : " + b2);
		System.out.println("加法操作 : " + b2.add(b1)); 
		System.out.println("减法操作 : " + b2.subtract(b1)); //864197532     b2 - b1
		System.out.println("乘法操作 : " + b2.multiply(b1));
		System.out.println("除法操作 :  " + b2.divide(b1)); //8   b2 / b1(仍是向下取整)
		System.out.println("求出最大数 : " + b2.max(b1));
		System.out.println("..." + b2.min(b1));
		BigInteger result[] = b2.divideAndRemainder(b1); //求出余数的除法操作
		System.out.println("商是 : " + result[0] + ",余数是 : " + result[1]); //商是 : 8,余数是 : 9
		System.out.println("等价性是 : " + b1.equals(b2)); //等价性是 : false
		int flag = b1.compareTo(b2);
		if (flag == -1)
			System.out.println("b1 < b2");
		else if (flag == 0)
			System.out.println("b1 == b2");
		else 
			System.out.println("b1 > b2");
	}
}

import java.math.BigDecimal;

public class BigDecimalTest {
	public static void main(String[] args){
		BigDecimal b1 = new BigDecimal("123456789.987654321");
		BigDecimal b2 = new BigDecimal("987654321.123456789");
		//输出
		//加法
		//减法
		//乘法
		
		//BigDecimal做除法操作,需要指定位数进行截断,防止无限循环,或者包含在try-catch中
		System.out.println("除法 : " + b2.divide(b1, 10, BigDecimal.ROUND_HALF_UP)); //8.0000000099 小数点后十位
		
		//最大数
		//最小数
		
		int flag = b1.compareTo(b2);
		
		//尽量采用字符串赋值,这样精度更准确
		System.out.println(new BigDecimal("2.3")); //2.3
		System.out.println(new BigDecimal(2.3)); //2.29999999999999982236431605997495353221893310546875
		
		BigDecimal num1 = new BigDecimal("10");
		BigDecimal num2 = new BigDecimal("3");
		//截断
		BigDecimal num3 = num1.divide(num2, 3, BigDecimal.ROUND_HALF_UP); //3.333
		System.out.println(num3);
	}
}

随机数类

Random随机数

​ nextInt() 返回一个随机int

​ nextInt(int a) 返回一个[0,a)之间的随机int

​ nextDouble() 返回一个[0.0,1.0]之间的随机double

​ ints 方法批量返回随机数数组

Math.random()

返回一个[0.0,1.0]随机double

import java.util.Random;

public class RandomTest {
	public static void main(String[] args){
		
		//第一种方法,使用Random类,随机生成在int(咳咳)范围内的随机数
		Random rd = new Random();
		System.out.println(rd.nextInt()); //141687037
		System.out.println(rd.nextInt(100)); //10
		System.out.println(rd.nextLong()); //947969735225438262
		System.out.println(rd.nextDouble());
		
		//第二种方法 生成一个范围内的随机数,例如0到10之间的随机数
		System.out.println(Math.round(Math.random() * 10)); //10 //round四舍五入
		
		//jdk8新增方法
		int[] arr = rd.ints(10).toArray(); //生成10个int范围类的个数
		for (int i = 0; i < arr.length; i ++ )
		{
			System.out.println(arr[i]);
		}
		System.out.println("============================");
		
		arr = rd.ints(5, 10, 100).toArray(); //5个10到100的int
		for (int i = 0; i < arr.length; i ++ )//奇怪的是这里的length也变为5
		{
			System.out.println(arr[i]);
		}
		
		System.out.println("============================");
		
		arr = rd.ints(10).limit(5).toArray(); //limit限定5个,返回5个
		for (int i = 0; i < arr.length; i ++ ) //输出了5个
		{
			System.out.println(arr[i]);
		}
	}
}

数字工具类

java.lang.Math

​ 绝对值函数abs

​ 对数函数log

​ 比较函数max,min

​ 幂函数pow

​ 四舍五入函数round

​ 向下取整floor

​ 向上取整ceil

public class MathTest {
	public static void main(String[] args){
		System.out.println(Math.abs(-5));
		System.out.println(Math.max(-7,-2));
		System.out.println(Math.pow(-5,  2)); //25.0
		System.out.println(Math.round(4.5)); //5
		System.out.println(Math.floor(4.5)); //4.0
		System.out.println(Math.ceil(4.5)); //5.0
	}
}

第三节.字符串相关类

String

​ 是java中使用频率最高的类

​ 是一个不可变对象,加减操作性能较差,只读

public class StringTest {
	public static void main(String[] args){
		String a = "123;456;789;123 ";
		System.out.println(a.charAt(0)); //返回第0个元素
		System.out.println(a.indexOf(";")); //返回第一个;的位置
		
		System.out.println(a.concat(";000")); //连接一个新字符串并返回,a不变
		
		System.out.println(a.contains("000"));  //判断a是否包含000 //false
		System.out.println(a.endsWith("000")); //判断是否以000结尾 //false
		System.out.println(a.equals("000")); //判断是否等于000 //false
		System.out.println(a.equalsIgnoreCase("000")); //判断在忽略大小写情况下是否等于000
		
		System.out.println(a.length()); //长度
		
		System.out.println(a.trim()); //返回a去除前后空格后的字符串(无法去除字符串中间的空格),a不变
		
		String[] b = a.split(";"); //将a字符串按照;分割成数组
		for (int i = 0; i < b.length; i ++ )
		{
			System.out.println(b[i]);
		}
		
		System.out.println("=========================");
		
		System.out.println(a.substring(2, 5)); //截取a第二个到第五个字符,a不变 //3;4 因此可能不包括第五个,左闭右开
		System.out.println(a.replace("1", "a")); //将所有1用a替代,区别:旧字符串替换成新字符串 //a23;456;789;a23 
		System.out.println(a.replaceAll("1", "a")); //同上,区别:第一个参数是正则表达式
		
		System.out.println("=========================");
		
		String s1 = "12345?6789";
		String s2 = s1.replace("?", "a");
		String s3 = s1.replaceAll("[?]", "a");
		//这里的[?]才表示字符问号,这样才能正常替换
		System.out.println(s2); //12345a6789
		System.out.println(s3); //12345a6789
	}
}

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

可变字符串

​ StringBuffer(字符串加减,同步,性能好

​ StringBuilder(字符串加减,不同步,性能更好

​ 方法一样,区别在于同步

​ append, insert, delete, replace, substring

​ length字符串实际大小。capacity字符串占用空间大小

​ trimToSize() 去除空隙,将字符串存储压缩到实际大小

​ 如果大量append,实现预估大小,再调用相应构造函数

public class StringBufferReferenceTest {
	public static void main(String[] args){
		StringBuffer sb1 = new StringBuffer("123");
		StringBuffer sb2 = sb1;
		
		sb1.append("123443429430");
		System.out.println(sb2); //sb1和sb2还是指向同一个内存的,StringBuffer是可变对象,与String不同
	}
}

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

public class StringBuffwerCapacityTest {
	public static void main(String[] args){
		//StringBuffer的初始大小为(16 + 初始字符串长度) 即capacity = 16 + 初始字符串长度
		//length实际长度 capacity存储空间大小
		StringBuffer sb1 = new StringBuffer();
		System.out.println("sb1 length : " + sb1.length()); //0
		System.out.println("sb1 capacity : " + sb1.capacity()); //16
		System.out.println("=====================");
		
		StringBuffer sb2 = new StringBuffer("123");
		sb2.append("456");
		System.out.println("sb2 length : " + sb2.length()); //6
		System.out.println("sb2 capacity : " + sb2.capacity()); //19
		System.out.println("=====================");
		
		sb2.append("7890123456789");
		System.out.println("sb2 length : " + sb2.length()); //19
		System.out.println("sb2 capacity : " + sb2.capacity()); //19
		System.out.println("=====================");
		
		sb2.append("0");
		System.out.println("sb2 length : " + sb2.length()); //20
		System.out.println("sb2 capacity : " + sb2.capacity()); //40
		//一旦length大于capacity,capacity便在前一次的基础上加1后翻倍
		System.out.println("=====================");
		
		//当前sb2 length20 capacity 40 再append70个字符,超过(加1再2倍数额)
		sb2.append("1222389178032432o4u93289324932142343423432");
		System.out.println("sb2 length : " + sb2.length()); //90
		System.out.println("sb2 capacity : " + sb2.capacity()); //90
		//如果append的对象很长,超过(加1再2倍数额),将以最新的长度更换
		
		System.out.println("=====================");
		
		sb2.append("0");
		System.out.println("sb2 length : " + sb2.length()); //91
		System.out.println("sb2 capacity : " + sb2.capacity()); //182
		sb2.trimToSize();
		System.out.println("===========after time==========");
		System.out.println("sb2 length : " + sb2.length()); //91
		System.out.println("sb2 capacity : " + sb2.capacity()); //91
	}
}

第九章.java异常和异常处理

第一节.java异常分类

异常

​ 程序不正常的行为或状态

​ int a = 5 / 0;

​ 数组越界访问

​ 读取文件,结果文件不存在

异常处理

​ 程序回到安全状态

​ 允许用户保存结果,并以适当方式关闭程序

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

Throwable : 所有错误的祖先

Error : 系统内部错误或者资源耗尽,不管

Exception : 程序有关的异常,重点关注

RuntimaException : 程序自身的错误

​ 5 / 0, 空指针, 数组越界

非RuntimeException : 外界相关的错误

​ 打开一个不存在的文件

​ 加载一个不存在的类

· CheckException非RuntimeException, 编译器会辅助检查的,以发生后处理为主;而RuntimeException是UncheckedException ,程序必须处理,以预防为主

第二节.java异常处理

try - catch - finally

​ 一种保护代码正常运行的机制

​ try必须有,catch和finally至少要有一个

try : 正常业务逻辑代码

catch :当try发生异常,将执行catch代码,若无,绕之

finally : 当try或catch执行结束后,必须要执行finally

public class TryDemo {
	
	public static void main(String[] args) {
		try
		{
			int a = 5 / 2;
			System.out.println("a is " + a);
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		finally
		{
			System.out.println("Phrase 1 is over");
		}
		
		try
		{
			int a = 5 / 0;
			System.out.println("a is " + a);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
		finally
		{
			System.out.println("Phrase 2 is over");
		}
		
		try
		{
			int a = 5 / 0;
			System.out.println("a is " + a);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
			int a = 5 / 0;
			//catch内部再次发生异常,也不影响finally的正常运行
		}
		finally
		{
			System.out.println("Phrase 3 is over");
		}
	}
}

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

catch块可以有多个,一个异常只能进入一个catch块(catch块的异常匹配是从上到下进行匹配的,所以小异常写前面 ),如果没有一个匹配,catch不会被触发,直接finally

throws声明异常

·方法存在可能异常的语句,但不处理那么可以使用throws来声明异常

·调用带有throws异常(checkedException)的方法,要么处理这些异常,或者再次向外抛出throws,知道main函数为止

//结果是调用栈,先看最后一行,先异常
public class ThrowsDemo {
	public static void main(String[] args) {
		try //第4到11行就是处理第22行没有处理的异常
		{
			int result = new Test().divide(3,  1);
            //要new才可以用它这个方法因为divide方法不是static的
			System.out.println("the 1st result is " + result);
		}
		catch (ArithmeticException ex){
			ex.printStackTrace();
		}
		int result = new Test().divide(3,  0); //爆发异常
		System.out.println("the 2nd result is " + result);
	}
}

class Test
{
	//ArithmeticException is a RuntimeException, not checkedException
	public int divide(int x, int y) throws ArithmeticException //因为在22行没有处理,所以抛出
	{
		int result = x / y;
		return result;
	}
}

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

public class MyExceptionTest {
	public static void testException() throws MyException {
		throw new MyException("10001", "The reason of myException");
	}
	
	public static void main(String[] args) {
		try
		{
			MyExceptionTest.testException();
		}
		catch (MyException e)
		{
			e.printStackTrace();
			System.out.println("returnCode : " + e.getReturnCode);
			System.out.println("returnMsg : " + e.getReturnMsg);
		}
	}
}

public class MyExceptionTest {
	public static void testException() throws MyException {
        //在方法内部程序中,抛出异常采用throw关键字
        //在方法头部声明中,声明异常采用throws关键字
		throw new MyException("10001", "The reason of myException");
	}
	
	public static void main(String[] args) throws MyException {
		MyExceptionTest.testException();
	}
}

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

·一个方法被覆盖,覆盖它的方法必须抛出相同的异常,或者异常的子类

·如果父类的方法抛出多个异常,那么重写的子类方法必须抛出那些异常的子集,也就是不能抛出新的异常

·重写方法时,子类方法所抛出的异常不能超出父类方法的异常范围

第三节.自定义异常

·自定义异常 需要继承Exception类或其子类

​ 继承自Exception,就变成CheckedException

​ 继承自RuntimeException,就变成UncheckedException

·自定义重点在构造函数

​ 调用父类Exception的message构造函数

​ 可以自定义自己的成员变量

·在程序中采用throw主动抛出异常

public class MyException extends Exception{
	
	private String returnCode; //异常对应的返回码
	private String returnMsg; //异常对应的描述信息
	
	public MyException()
	{
		super();
	}
	
	public MyException(String returnMsg)
	{
		super(returnMsg);
		this.returnMsg =returnMsg;
	}
	
	public MyException(String returnCode, String returnMsg)
	{
		super();
		this.returnCode = returnCode;
		this.returnMsg = returnMsg;
	}
	
	public String getReturnCode()
	{
		return returnCode;
	}
	
	public String getReturnMsg ()
	{
		return returnMsg;
	}
}

public class DivideByMinusException extends Exception{
	int divisor;
	public DivideByMinusException(String msg, int divisor)
	{
		super(msg);
		this.divisor = divisor;
	}
	public int getDivisor()
	{
		return this.getDivisor();
	}
}

public class Student {
	public int divide(int x, int y)
	{
		return x / y;
	}
	public static void main(String[] args) throws DivideByMinusException {
		Student newton = new Student();
		newton.divide5(5, -2);
	}
	
	public int divide2(int x, int y)
	{
		int result;
		try
		{
			result = x / y;
			System.out.println("result is " + result);
		}
		catch (ArithmeticException ex)
		{
			System.out.println(ex.getMessage());
			return 0;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
			return 0;
		}
		return result;
	}
	
	//ArithmeticException is a unchecked Exception,编译器可以不管
	public int divide3(int x, int y) throws ArithmeticException {
		return x / y;
	}
	
	//尽管divide4调用divide3,但可以不throws,因为编译器不管aex
	public int divide4(int x, int y)
	{
		return divide3(x, y);
	}
	
	public int divide5(int x, int y) throws DivideByMinusException {
		try
		{
			if (y < 0 )
			{
				throw new DivideByMinusException("The divisor is negative", y);
			}
			return divide3(x, y);
		}
		catch(ArithmeticException ex)
		{
			ex.printStackTrace();
			return 0;
		}
	}
}

·对于CheckedException,编译器采用调用者处理要么采用try-catch-finally处理,要么采用throws声明异常

·而UnCheckException,编译器不管,都不用throws声明异常

第十章.java数据结构

第一节.数组

·数组是一个存放多个数据的容器

​ 数据是同一种类型

​ 所有的数据是线性规则排列

​ 可通过位置索引来快速定位访问元素

​ 需明确容器的长度

·java数组定义和初始化

int a[]; //a还没有new操作,实际上是null,也不知道内存位置
int[] b; //b还没有new操作,实际上是null,也不知道内存位置
int[] c = new int[2]; //c有两个元素,都是0
c[0] = 10; c[1] = 20;

int d[] = new int[]{0, 2, 4}; //d有3个1元素,0,2,4,同时定义和初始化
int d1[] = {1, 3, 5}; //d1有3个元素,1,3,5,同时定义和初始化

//注意声明变量时候没有分配内存,就不需要指定大小

·数组遍历 : 2种方法

for (int i = 0; i < d.length; i ++ )
{
	System.out.println(d[i]);
}

//for-each不会越界
for (int e : d)
{
	System.out.println(e);
}

·多维数组

​ 数组的数组

​ 存储是按照行存储原则

//规则数组
int a[][] = new int[2][3];

//不规则数组
int b[][];
b = new int[3][];
b[0] = new int[3];
b[1] = new int[4];
b[2] = new int[5];
int k = 0;
for (int i = 0; i < a.length; i ++ )
{
    for (int j = 0; j < a[i].length; j ++ )
    {
        a[i][j] = ++ k;
    }
}

for (int[] items : a)
{
    for (int item : items)
    {
        System.out.println(item + ", ");
    }
    System.out.println();
}

第二节.JCF

·容器 : 能够存放数据的空间结构

·容器框架 :为表示和操作容器而规定的一种标准体系结构

​ 对外的接口

​ 接口的实现

​ 算法

·JCF的集合接口是Collection

​ add, contains, remove, size

​ iterator

·JCF的迭代器接口是Iterator

​ hasNext

​ next

​ remove

·JCF主要的数据结构实现类

​ 列表 List…

​ 集合 Set…

​ 映射 Map…

·JCF主要的算法类(工具类)

​ Arrays : 对数组进行查找和排序等

​ Collections : 对Collection及其子集进行排序和查找等

第三节.列表List

·List : 列表

有序的Collection

​ 允许重复元素

​ {1, 2, 4, {5, 2}, 1, 3} //元素可以支持不同类型,嵌套也可以

·List主要实现

​ ArrayList(非同步)

​ LinkedList(非同步)

​ Vector(同步)

ArrayList

​ 以数组实现的列表,不支持同步

​ 利用索引位置可以快速定位访问

​ 不适合制定位置的插入,删除操作

​ 适合变动不大,主要用于查询的数据

​ 和Java数组相比,其容量是可动态调整

​ ArrayList在元素填满容器时会自动扩充容器大小的50%

add(a), add(a, b), remove(a), get(a), size()
import java.util.ArrayList;
//Vector几乎和ArrayList一样,除了Vector本身是同步的
import java.util.Iterator;

public class ArrayListTest {
	public static void main(String[] args) {
		ArrayList<Integer> al = new ArrayList<Integer>(); //泛型表示
		//ArrayList中只能放对象,所以add(3)时,会把普通int变量3自动装箱为Integer(3)的对象,然后放入容器中
		al.add(3);
		al.add(2);
		al.add(1);
		al.add(4);
		al.add(5);
		al.add(6);
		al.add(new Integer(6));
		
		System.out.println("The third element is "); 
		System.out.println(al.get(3)); //得到下标为3(从0开始)的元素
		al.remove(3); //删除第4个元素,后面的元素往前移动
		al.add(3, 9); //把9插入到第4个元素,后面的元素往后移动
		
		System.out.println("========遍历方法========");
		
		ArrayList<Integer> as = new ArrayList<Integer>(100000);
		for (int i = 0; i < 100000; i ++) 
		{
			as.add(i);
		}
		traverseByIterator(as); //ArrayList来说比较慢
		traverseByIndex(as);
		traverseByFor(as);
	}
	
	public static void traverseByIterator(ArrayList<Integer> al)
	{
		long startTime = System.nanoTime();
		System.out.println("迭代器遍历 : ");
		Iterator<Integer> iter1 = al.iterator();
		while (iter1.hasNext())
		{
			iter1.next();
		}
		long endTime = System.nanoTime();
		long duration = endTime - startTime;
		System.out.println(duration + "纳秒");
	}
	
	public static void traverseByIndex(ArrayList<Integer> al)
	{
		long startTime = System.nanoTime();
		System.out.println("随机索引值遍历 : ");
		for (int i = 0; i < al.size(); i ++ )
		{
			al.get(i);
		}
		long endTime = System.nanoTime();
		long duration = endTime - startTime;
		System.out.println(duration + "纳秒");
	}
	
	public static void traverseByFor (ArrayList<Integer> al)
	{
		long startTime = System.nanoTime();
		System.out.println("for-each遍历 : ");
		for (Integer item : al)
		{
			;
		}
		long endTime = System.nanoTime();
		long duration = endTime - startTime;
		System.out.println(duration + "纳秒");
	}
}

LinkedList

​ 以双向链表实现的列表,不支持同步

​ 可被当做堆栈,队列,双端队列进行操作

顺序访问高效(采用下标法遍历不算顺序访问),随机访问较差,中间插入和删除高效

​ 适用于经常变化的数据

add(a), add(a, b), addFirst(a), get(a), remove(a), size()
import java.util.Iterator;
import java.util.LinkedList;

public class LinkedListTest {
	public static void main(String[] args) {
		LinkedList<Integer> ll = new LinkedList<Integer>();
		ll.add(3);
		ll.add(2);
		ll.add(5);
		ll.add(6);
		ll.add(6);
		System.out.println(ll.size());
		ll.addFirst(9); //在头部增加一个9
		ll.add(3, 10); //把4插入到第4个元素,。。。
		ll.remove(3);
		
		LinkedList<Integer> list = new LinkedList<Integer>(); //不能指定大小?
		for (int i = 0; i < 100000; i ++ )
		{
			list.add(i);
		}
		
		traverseByIterator(list);
		traverseByIndex(list); //对于LinkedList不要采用这个(随机访问遍历),会慢几十倍
		traverseByFor(list);
	}
	
	public static void traverseByIterator(LinkedList<Integer> list)
	{
		Iterator<Integer> iter1 = list.iterator();
		while (iter1.hasNext())
		{
			iter1.next();
		}
	}
	
	public static void traverseByIndex(LinkedList<Integer> list)
	{
		for (int i = 0; i < list.size(); i ++ )
		{
			list.get(i);
		}
	}
	
	public static void traverseByFor (LinkedList<Integer> list)
	{
		for (Integer item : list)
		{
			;
		}
	}
}

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

ps : 这里的add是add(0, i) ,即每次都向头部增加一个元素,remove也是每次移除头部元素remove(0)

Vector(同步)

​ 和ArrayList相似,可变数组实现的列表

​ Vector同步,适合在多线程下使用

​ 官方文档建议在非同步(即不是多线程)情况下,优先使用ArrayList

​ Vector和ArrayList几乎是差不多,由于同步的,性能比ArrayList稍差

//add(a), add(a, b), size(), remove(a), get(a);
import java.util.Vector;

public class VectorTest {
	public static void main(String[] args) {
		Vector<Integer> v = new Vector<Integer>();
		v.add(1);
		v.add(3);
		v.remove(1);
		v.add(0, 1);
		System.out.println(v.size());
		
		Vector<Integer> v2 = new Vector<Integer> (100000);
		for (int i = 0; i < 100000; i ++ )
		{
			v2.add(i);
		}
		
		traverseByIterator(v2);
		traverseByIndex(v2);
		traverseByFor(v2); //快
	}
}

总结

​ 同步,Vector

​ 非同步,根据数据操作特点使用ArrayList/LinkedList

第四节.集合Set

集合Set

​ 确定性 : 对任意对象都能判断是否属于集合

​ 互异性 : 集合内每个元素都是不同的,注意是内容互异

​ 无序性 : 集合内的顺序无关

Java中的集合接口Set

​ HashSet(基于散列函数的集合,无序,不支持同步)

​ TreeSet(基于树结构的集合,可排序的,不支持同步)

​ LinkedHashSet(基于散列函数和双向链表的集合,可排序的,不支持同步)

HashSet

​ 基于HashMap实现,可以容纳null元素,不支持同步

​ Set s = Collections.synchronizedSet(new HashSet(…));

​ add

​ clear

​ contains

​ remove

​ size

​ retainAll 计算两个集合交集

import java.util.HashSet;
import java.util.Iterator;

public class HashSetTest {
	public static void main(String[] args) {
		HashSet<Integer> hs = new HashSet<Integer>();
		hs.add(null);    //遍历时会输出null
		hs.add(1000);
		hs.add(20);
		hs.add(3);
		hs.add(5000000);
		hs.add(3); //3重复,所以无效
		hs.add(null); //null重复
		System.out.println(hs.size()); //5
		if (!hs.contains(6))
		{
			hs.add(6);
		}
		System.out.println(hs.size()); //6
		hs.remove(4);
		System.out.println(hs.size()); //6, 因为没有4这个元素,无效
		//hs.clear();
		//System.out.println(hs.size());    //0
		
		System.out.println("=============for循环遍历======");
		for (Integer item : hs)     //输出和插入顺序不一样,说明HashSet是一个无序的集合结构
		{
			System.out.println(item);
		}
		
		System.out.println("==============测试集合交集=====");
		
		HashSet<String> set1 = new HashSet<String>();
		HashSet<String> set2 = new HashSet<String>();
		
		set1.add("a");
		set1.add("b");
		set1.add("c");
		
		set2.add("c");
		set2.add("d");
		set2.add("e");
		
		System.out.println(set1);      //[a, b, c]
		
		//交集
		set1.retainAll(set2);  //set1中不是交集的就会全部被删除
		
		System.out.println("交集是 : " + set1);    //交集是 : [c]
		
		System.out.println("============测试多种遍历方式速度======");
		
		HashSet<Integer> hs2 = new HashSet<Integer>();
		for (int i = 0; i < 100000; i ++ )
		{
			hs2.add(i);
		}
		traverseByIterator(hs2);
		traverseByFor(hs2);  //比迭代器快不少
	}
	
	public static void traverseByIterator(HashSet<Integer> hs)
	{
		Iterator<Integer> iter1 = hs.iterator();
		while (iter1.hasNext())
		{
			iter1.next();
		}
	}
}

LinkedHashSet

​ 继承HashSet,也是基于HashMap实现的,可以容纳null元素

​ 不支持同步

​ Set s = Collections.synchronizedSet(new LinkedHashSet(…));

​ 方法和HashSet基本一致

​ add, clear, contains, remove, size

​ 通过一个双向链表维护插入顺序

​ LinkedHashSet是保留顺序的,其遍历顺序和插入顺序一致;而HashSet没有保留顺序,其遍历顺序无序

TreeSet

​ 基于TreeMap实现,不可以容纳null元素,不支持同步

​ SortedSet s = Collections.synchronizedSortedSet(new TreeSet(…));

​ add

​ clear

​ contains

​ remove

​ size

​ 根据compareTo方法或者制定Comparator排序

​ HashSet是无序输出的,LinkedHashSet是按照插入顺序进行遍历输出的,TreeSet是按照所存储对象大小升序输出的

总结

​ HashSet, LinkedHashSet, TreeSet的元素都只能是对象(尽管add(20),变成了对象放进去)

​ //当对象不是前面这种而是复杂时:

HashSet和LinkedHashSet判断元素重复的原则

​ 判定两个元素的hashCode返回值是否相同,若不同,返回false1

​ 若两者hashCode相同,判定equals方法,若不同,false;否则返回true

​ hashCode和equals方法是所有类都有的,因为Object类有

TreeSet判定元素重复的原则(添加到TreeSet的,必须实现compareTo方法)(Integer类有实现,所以可以)

​ 需要元素继承自Comparable接口

​ 比较两个元素的compareTo方法

HashSet和LinkedHahSet:

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

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

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

通常这三个方法改写都是三位一体的

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

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

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

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

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

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

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

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

说明HashSet每次加进去都会判定HashCode,只有在HashCode一样的情况下才会判定equals;根本没有调用到compareTo方法(Tiger类Test中)

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

第五节.映射Map

Map映射

​ 数学定义 : 两个集合之间的元素对应关系

​ 一个输入对应一个输出

​ {1, 张三},{2,李四},{Key,Value},键值对,K-V对

java中Map

​ Hashtable(同步,慢,数据量小) (注意这个t是小写的,以前设计错误)

​ HashMap(不支持同步,快,数据量大)

​ Properties(同步,文件形式,数据量小)

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值