目录
第三章.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(同步,文件形式,数据量小)