面向对象编程(高级部分) 类变量和类方法 类变量 类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
类变量定义语法:
访问修饰符 static 数据类型 变量名; [推荐]
static 访问修饰符 数据类型 变量名:
访问类变量
类名.类变量名 [推荐]
对象名.类变量名
【静态变量的访问修饰符的访问权限和范围和普通属性是一样的】
类方法 类方法也叫静态方法。
类方法定义语法:
访问修饰符 static 数据返回类型 方法名(){ }【推荐】 static 访问修饰符 数据返回类型 方法名(){ }
类方法的调用
使用方式:类名.类方法名 或者 对象名.类方法名
【满足访问修饰符的访问权限和】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class StaticMethod { public static void main (String[] args) { Stu tom = new Stu ("tom" ); Stu.payFee(100 ); Stu mary = new Stu ("mary" ); Stu.payFee(200 ); Stu.showFee(); System.out.println("9开平方的结果是=" + Math.sqrt(9 )); System.out.println(MyTools.calSum(10 , 30 )); } } class MyTools { public static double calSum (double n1, double n2) { return n1 + n2; } } class Stu { private String name; private static double fee = 0 ; public Stu (String name) { this .name = name; } public static void payFee (double fee) { Stu.fee += fee; } public static void showFee () { System.out.println("总学费有:" + Stu.fee); } }
小结
1)类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:类方法中无this的参数,普通方法中隐含着this的参数。
2)类方法可以通过类名调用,也可以通过对象名调用。[举例]
3)普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用。
4)类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以。
5)类方法(静态方法)中只能访问静态变量或静态方法 。
6)普通成员方法,既可以访问非静态成员,也可以访问静态成员。
理解main方法
1) 在 main()方法中,我们可以直接调用 main 方法所在类的静态方法或静态属性。 2) 但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Main01 { private static String name = "JAVA学习" ; private int n1 = 10000 ; public static void hi () { System.out.println("Main01的 hi方法" ); } public void cry () { System.out.println("Main01的 cry方法" ); } public static void main (String[] args) { System.out.println("name=" + name); hi(); Main01 main01 = new Main01 (); System.out.println(main01.n1); main01.cry(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Main02 { public static void main (String[] args) { for ( int i = 0 ; i < args.length; i++ ) { System.out.println("args[" + i + "] = " + args[i]); } } } args[0 ] = 北京 args[1 ] = 天津 args[2 ] = 上海 args[3 ] = Jack args[4 ] = Tom
代码块 代码化块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。 但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
[修饰符]{
};
说明注意
1) 修饰符 可选,要写的话,也只能写static
2) 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块
3) 逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
4) ;号可以写上,也可以省略
好处
1)相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
2)场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性
细节
static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行。
1) 类什么时候被加载 ①创建对象实例时(new) ②创建子类对象实例,父类也会被加载 ③使用类的静态成员时(静态属性,静态方法)
普通的代码块,在创建对象实例时,会被隐式的调用。 被创建一次,就会调用一次。 如果只是使用类的静态成员时,普通代码块并不会执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class CodeBlock { public static void main (String[] args) { AA a = new AA (); System.out.println(CC.n1); DD d = new DD (); DD d2 = new DD (); System.out.println(DD.n2); } } class DD { public static int n2 = 888 ; static { System.out.println("DD的静态代码块..." ); }; { System.out.println("DD的普通代码块..." ); } } class CC { public static int n1 = 999 ; static { System.out.println("CC的静态代码块..." ); } } class BB { static { System.out.println("BB的静态代码块..." ); } } class AA extends BB { static { System.out.println("AA的静态代码块..." ); } }
创建一个对象时,在一个类调用顺序是:
①调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
②调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
③调用构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class CodeBlock02 { public static void main (String[] args) { A a = new A (); } } class A { { System.out.println("A 普通代码块01" ); } private int n2 = getN2(); static { System.out.println("A 静态代码块01" ); } private static int n1 = getN1(); public static int getN1 () { System.out.println("getN1被调用..." ); return 100 ; } public int getN2 () { System.out.println("getN2被调用..." ); return 200 ; } public A () { System.out.println("A() 构造器被调用" ); } } A 静态代码块01 getN1被调用... A 普通代码块01 getN2被调用... A() 构造器被调用
构造器的最前面其实隐含了super()和调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的。
创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
①父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
②子类的静态代码块和静态属性(优先级一样,按定义顺序执行) ③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
④父类的构造方法 ⑤子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
⑥子类的构造方法
静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 public class CodeBlock03 { public static void main (String[] args) { new C02 (); } } class A02 { private static int n1 = getVal01(); static { System.out.println("A02的一个静态代码块.." ); } { System.out.println("A02的第一个普通代码块.." ); } public int n3 = getVal02(); public static int getVal01 () { System.out.println("getVal01" ); return 10 ; } public int getVal02 () { System.out.println("getVal02" ); return 10 ; } public A02 () { System.out.println("A02的构造器" ); } } class C02 { private int n1 = 100 ; private static int n2 = 200 ; private void m1 () { } private static void m2 () { } static { System.out.println(n2); m2(); } { System.out.println(n1); System.out.println(n2); m1(); m2(); } } class B02 extends A02 { private static int n3 = getVal03(); static { System.out.println("B02的一个静态代码块.." ); } public int n5 = getVal04(); { System.out.println("B02的第一个普通代码块.." ); } public static int getVal03 () { System.out.println("getVal03" ); return 10 ; } public int getVal04 () { System.out.println("getVal04" ); return 10 ; } public B02 () { System.out.println("B02的构造器" ); } }
单例设计模式 单例(单个的实例)
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
单例模式有两种方式:1)饿汉式2)懒汉式
饿汉式和懒汉式单例模式的实现。步骤如下: 1)构造器私有化=》防止直接new
2)类的内部创建对象
3)向外暴露一个静态的公共方法。getInstance
4)代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class SingleTon01 { public static void main (String[] args) { GirlFridend instance = GirlFridend.getInstance(); System.out.println(instance); GirlFridend instance2 = GirlFridend.getInstance(); System.out.println(instance2); System.out.println(instance == instance2); } } class GirlFridend { private String name; private static GirlFridend gf = new GirlFridend ("小红红" ); private GirlFridend (String name) { this .name = name; } public static GirlFridend getInstance () { return gf; } @Override public String toString () { return "GirlFridend{" + "name='" + name + '\'' + '}' ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class SingleTon02 { public static void main (String[] args) { Cat cat = Cat.getInstance(); System.out.println(cat); Cat cat2 = Cat.getInstance(); System.out.println(cat2); System.out.println(cat2 == cat); } } class Cat { private String name; public static int n1 = 777 ; private static Cat cat; private Cat (String name) { System.out.println("构造器被调用..." ); this .name = name; } public static Cat getInstance () { if (cat == null ) { cat = new Cat ("阿白" ); } return cat; } @Override public String toString () { return "Cat{" + "name='" + name + '\'' + '}' ; } }
饿汉式和懒汉式的区别
二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
final关键字 final可以修饰类、属性、方法和局部变量。 在某些情况下,可能有以下需求 ,就会使用到final:
1)当不希望类被继承时,可以用final修饰。
2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。【访问修饰符 final 返回类型 方法名】
3)当不希望类的的某个属性的值被修改,可以用final修饰。
4)当不希望某个局部变量被修改,可以使用final修饰
注意
final修饰的属性又叫常量,一般用XX_XX_X来命名
final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一: ①定义时:如public final double TAX_RATE=0.08;
②在构造器中。
③在代码块中。
如果final修饰的属性是静态的,则初始化的位置只能是①定义时②在静态代码块不能在构造器中赋值。
final类不能继承,但是可以实例化对象。
如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class Final01 { public static void main (String[] args) { CC cc = new CC (); new EE ().cal(); } } class AA { public final double TAX_RATE = 0.08 ; public final double TAX_RATE2 ; public final double TAX_RATE3 ; public AA () { TAX_RATE2 = 1.1 ; } { TAX_RATE3 = 8.8 ; } } class BB { public static final double TAX_RATE = 99.9 ; public static final double TAX_RATE2 ; static { TAX_RATE2 = 3.3 ; } } final class CC { }class DD { public final void cal () { System.out.println("cal()方法" ); } } class EE extends DD { }
6) final不能修饰构造方法(即构造器) 6) 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。 6) final和static往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理。 6) 包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Final02 { public static void main (String[] args) { System.out.println(BBB.num); } } class BBB { public final static int num = 10000 ; static { System.out.println("BBB 静态代码块被执行" ); } } final class AAA { }
抽象类 1)用abstract关键字来修饰一个类时,这个类就叫抽象类访问。【修饰符 abstract 类名{}】 2)用abstract关键字来修饰一个方法时,这个方法就是抽象方法。【访问修饰符 abstract 返回类型 方法名(参数列表); //没有方法体】 3)抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类() 4)抽象类,在框架和设计模式使用较多。
细节
抽象类不能被实例化
抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
一旦类包含了abstract方法,则这个类必须声明为abstract
abstract只能修饰类和方法,不能修饰属性和其它的
抽象类可以有任意成员【抽象类本质还是类】,比如:非抽象方法,构造器、静态属性等等
抽象方法不能有主体,即不能实现
如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
抽象方法不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的
模板设计模式 基本介绍 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。模板设计模式能解决的问题 1)当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。 2)编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。
1 2 3 4 5 6 public class TestTemplate { public static void main (String[] args) { Sub sub = new Sub (); sub.calculateTime(); } }
1 2 3 4 5 6 7 8 9 10 11 12 abstract public class Template { public abstract void job () ; public void calculateTime () { long start = System.currentTimeMillis(); job(); long end = System.currentTimeMillis(); System.out.println("runtimes: " + (end - start) + " ms" ); } }
1 2 3 4 5 6 7 8 9 public class Sub extends Template { @Override public void job () { long num = 0 ; for (long i = 0 ; i < 100000 ; i++) { num += i; } } }
接口 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
语法: interface 接口名{
//属性
//抽象方法
} class 类名 implements 接口{ 自己属性; 自己方法; 必须实现的接口的抽象方法
}
注意
1)接口不能被实例化
2)接口中所有的方法是public方法,接口中抽象方法,可以不用abstract修饰
3)一个普通类实现接口,就必须将该接口的所有方法都实现
4)抽象类实现接口,可以不用实现接口的方法
5)一个类同时可以实现多个接口
6)接口中的属性,只能是final的,而且是 public static final修饰符。比如int a=1;实际上是 public static final int a=1; (必须初始化)
7)接口中属性的访问形式:接口名.属性名
8)接口不能继承其它的类,但是可以继承多个别的接口
9)接口的修饰符只能是 public和默认,这点和类的修饰符是一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public class ExtendsVsInterface { public static void main (String[] args) { LittleMonkey wuKong = new LittleMonkey ("悟空" ); wuKong.climbing(); wuKong.swimming(); wuKong.flying(); } } class Monkey { private String name; public Monkey (String name) { this .name = name; } public void climbing () { System.out.println(name + " 会爬树..." ); } public String getName () { return name; } } interface Fishable { void swimming () ; } interface Birdable { void flying () ; } class LittleMonkey extends Monkey implements Fishable , Birdable { public LittleMonkey (String name) { super (name); } @Override public void swimming () { System.out.println(getName() + " 通过学习,可以像鱼儿一样游泳..." ); } @Override public void flying () { System.out.println(getName() + " 通过学习,可以像鸟儿一样飞翔..." ); } }
接口多态 多态参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class InterfacePolyParameter { public static void main (String[] args) { IF if01 = new Monster (); if01 = new Car (); AAA a = new BBB (); a = new CCC (); } } interface IF {}class Monster implements IF {}class Car implements IF {}class AAA {} class BBB extends AAA {}class CCC extends AAA {}
多态数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package senior.interface_;public class InterfacePolyArr { public static void main (String[] args) { Usb[] usbs = new Usb [2 ]; usbs[0 ] = new Phone_ (); usbs[1 ] = new Camera_ (); for (int i = 0 ; i < usbs.length; i++) { usbs[i].work(); if (usbs[i] instanceof Phone_) { ((Phone_) usbs[i]).call(); } } } } interface Usb { void work () ; } class Phone_ implements Usb { public void call () { System.out.println("手机可以打电话..." ); } @Override public void work () { System.out.println("手机工作中..." ); } } class Camera_ implements Usb { @Override public void work () { System.out.println("相机工作中..." ); } }
多态传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class InterfacePolyPass { public static void main (String[] args) { IG ig = new Teacher (); IH ih = new Teacher (); } } interface IH { void hi () ; } interface IG extends IH { }class Teacher implements IG { @Override public void hi () { } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class InterfaceExercise { public static void main (String[] args) { } } interface A { int x = 0 ; } class B { int x = 1 ; } class C extends B implements A { public void pX () { System.out.println(A.x + " " + super .x); } public static void main (String[] args) { new C ().pX(); } }
内部类 一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员【类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class InnerClass01 { public static void main (String[] args) { } } class Outer { private int n1 = 100 ; public Outer (int n1) { this .n1 = n1; } public void m1 () { System.out.println("m1()" ); } { System.out.println("代码块..." ); } class Inner { } }
分类
如果定义类在局部位置(方法中/代码块):(1) 局部内部类 (2) 匿名内部类
定义在成员位置 :(1) 成员内部类 (2)静态内部类
局部内部类 说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
1.可以直接访问外部类的所有成员,包含私有的
2.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
3.作用域:仅仅在定义它的方法或代码块中。
4.局部内部类—-访问——>外部类的成员[访问方式:直接访间]
5.外部类—-访问——>局部内部类的成员访问方式:创建对象,再访问(注意:必须在作用域内)记住:(1)局部内部类定义在方法中/代码块(2)作用域在方法体或者代码块中(3)本质仍然是一个类
6.外部其他类—-不能访问——->局部内部类(因为局部内部类地位是一个局部变量)
7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class LocalInnerClass { public static void main (String[] args) { Outer02 outer02 = new Outer02 (); outer02.m1(); System.out.println("outer02的hashcode=" + outer02); } } class Outer02 { private int n1 = 100 ; private void m2 () { System.out.println("Outer02 m2()" ); } public void m1 () { final class Inner02 { private int n1 = 800 ; public void f1 () { System.out.println("n1=" + n1 + " 外部类的n1=" + Outer02.this .n1); System.out.println("Outer02.this hashcode=" + Outer02.this ); m2(); } } Inner02 inner02 = new Inner02 (); inner02.f1(); } }
匿名内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 public class AnonymousInnerClass { public static void main (String[] args) { Outer04 outer04 = new Outer04 (); outer04.method(); } } class Outer04 { private int n1 = 10 ; public void method () { IA tiger = new IA () { @Override public void cry () { System.out.println("老虎叫唤..." ); } }; System.out.println("tiger的运行类型=" + tiger.getClass()); tiger.cry(); tiger.cry(); tiger.cry(); Father father = new Father ("jack" ) { @Override public void test () { System.out.println("匿名内部类重写了test方法" ); } }; System.out.println("father对象的运行类型=" + father.getClass()); father.test(); Animal animal = new Animal () { @Override void eat () { System.out.println("小狗吃骨头..." ); } }; animal.eat(); } } interface IA { public void cry () ; } class Father { public Father (String name) { System.out.println("接收到name=" + name); } public void test () { } } abstract class Animal { abstract void eat () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public class AnonymousInnerClassDetail { public static void main (String[] args) { Outer05 outer05 = new Outer05 (); outer05.f1(); System.out.println("main outer05 hashcode=" + outer05); } } class Outer05 { private int n1 = 99 ; public void f1 () { Person p = new Person (){ private int n1 = 88 ; @Override public void hi () { System.out.println("匿名内部类重写了 hi方法 n1=" + n1 + " 外部内的n1=" + Outer05.this .n1 ); System.out.println("Outer05.this hashcode=" + Outer05.this ); } }; p.hi(); } } class Person { public void hi () { System.out.println("Person hi()" ); } public void ok (String str) { System.out.println("Person ok() " + str); } }
成员内部类 成员内部类是定义在外部类的成员位置,并且没有static修饰。
1.可以直接访问外部类的所有成员,包含私有的
2.可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
3.作用域和外部类的其他成员一样,为整个类体。在外部类的成员方法中创建成员内部类对象,再调用方法。
4.成员内部类—-访问——>外部类成员(比如:属性) [访问方式:直接访问]
5.外部类—-访问———>成员内部类(说明)访问方式:创建对象,再访问
6.外部其他类—-访问——>成员内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class MemberInnerClass01 { public static void main (String[] args) { Outer08 outer08 = new Outer08 (); outer08.t1(); Outer08.Inner08 inner08 = outer08.new Inner08 (); inner08.say(); Outer08.Inner08 inner08Instance = outer08.getInner08Instance(); inner08Instance.say(); } } class Outer08 { private int n1 = 10 ; public String name = "张三" ; private void hi () { System.out.println("hi()方法..." ); } public class Inner08 { private double sal = 99.8 ; private int n1 = 66 ; public void say () { System.out.println("n1 = " + n1 + " name = " + name + " 外部类的n1=" + Outer08.this .n1); hi(); } } public Inner08 getInner08Instance () { return new Inner08 (); } public void t1 () { Inner08 inner08 = new Inner08 (); inner08.say(); System.out.println(inner08.sal); } }
静态内部类 说明:静态内部类是定义在外部类的成员位置,并且有static修饰 1.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
2.可以添加任意访问修饰符(public.protected、默认、private),因为它的地位就是一个成员。
3.作用域:同其他的成员,为整个类体
4.静态内部类—-访问——>外部类(比如:静态属性)[访问方式:直接访问所有静 态成员]
5.外部类—-访问———>静态内部类访问方式:创建对象,再访问
6.外部其他类—-访问——->静态内部类
7.如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class StaticInnerClass01 { public static void main (String[] args) { Outer10 outer10 = new Outer10 (); outer10.m1(); Outer10.Inner10 inner10 = new Outer10 .Inner10(); inner10.say(); Outer10.Inner10 inner101 = outer10.getInner10(); System.out.println("============" ); inner101.say(); Outer10.Inner10 inner10_ = Outer10.getInner10_(); System.out.println("************" ); inner10_.say(); } } class Outer10 { private int n1 = 10 ; private static String name = "张三" ; private static void cry () {} static class Inner10 { private static String name = "JAVA 学习" ; public void say () { System.out.println(name + " 外部类name= " + Outer10.name); cry(); } } public void m1 () { Inner10 inner10 = new Inner10 (); inner10.say(); } public Inner10 getInner10 () { return new Inner10 (); } public static Inner10 getInner10_ () { return new Inner10 (); } }
枚举和注解 枚举 枚举属于一种特殊的类,里面只包含一组有限的特定的对象。
自定义实现枚举 进行自定义类实现枚举,有如下特点:
1) 构造器私有化 2) 本类内部创建一组对象[四个 春夏秋冬] 3) 对外暴露对象(通过为对象添加 public final static 修饰符) 4) 可以提供 get 方法,但是不要提供 set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class Enumeration02 { public static void main (String[] args) { System.out.println(Season.AUTUMN); System.out.println(Season.SPRING); } } class Season { private String name; private String desc; public static final Season SPRING = new Season ("春天" , "温暖" ); public static final Season WINTER = new Season ("冬天" , "寒冷" ); public static final Season AUTUMN = new Season ("秋天" , "凉爽" ); public static final Season SUMMER = new Season ("夏天" , "炎热" ); private Season (String name, String desc) { this .name = name; this .desc = desc; } public String getName () { return name; } public String getDesc () { return desc; } @Override public String toString () { return "Season{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}' ; } }
enum关键字实现枚举 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class Enumeration03 { public static void main (String[] args) { System.out.println(Season03.AUTUMN); System.out.println(Season03.SUMMER); } } enum Season03 { SPRING("春天" , "温暖" ), WINTER("冬天" , "寒冷" ), AUTUMN("秋天" , "凉爽" ), SUMMER("夏天" , "炎热" ); private String name; private String desc; private Season03 () { } private Season03 (String name, String desc) { this .name = name; this .desc = desc; } public String getName () { return name; } public String getDesc () { return desc; } @Override public String toString () { return "Season{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}' ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class EnumExercise01 { public static void main (String[] args) { Gender2 boy = Gender2.BOY; Gender2 boy2 = Gender2.BOY; System.out.println(boy); System.out.println(boy2 == boy); } } enum Gender2 { BOY , GIRL; }
enum常用方法
1) toString:Enum 类已经重写过了,返回的是当前对象 名,子类可以重写该方法,用于返回对象的属性信息 2) name:返回当前对象名(常量名),子类中不能重写 3) ordinal:返回当前对象的位置号,默认从 0 开始 4) values:返回当前枚举类中所有的常量 5) valueOf:将字符串转换成枚举对象,要求字符串必须 为已有的常量名,否则报异常! 6) compareTo:比较两个枚举常量,比较的就是编号!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class EnumMethod { public static void main (String[] args) { Season03 autumn = Season03.AUTUMN; System.out.println(autumn.name()); System.out.println(autumn.ordinal()); Season03[] values = Season03.values(); System.out.println("===遍历取出枚举对象(增强for)====" ); for (Season03 season: values) { System.out.println(season); } Season03 autumn1 = Season03.valueOf("AUTUMN" ); System.out.println("autumn1=" + autumn1); System.out.println(autumn == autumn1); System.out.println(Season03.AUTUMN.compareTo(Season03.SUMMER)); } }
enum 实现接口 1) 使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而 Java 是单继承机制。 2) 枚举类和普通类一样,可以实现接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class EnumDetail { public static void main (String[] args) { Music.CLASSICMUSIC.playing(); } } class A {} interface IPlaying { public void playing () ; } enum Music implements IPlaying { CLASSICMUSIC; @Override public void playing () { System.out.println("播放好听的音乐..." ); } }
注解 1) 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。 2) 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。 3) 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等。
基本的 Annotation 介绍 使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素 三个基本的 Annotation:
1) @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法 2) @Deprecated: 用于表示某个程序元素(类, 方法等)已过时 3) @SuppressWarnings: 抑制编译器警告
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class Override_ { public static void main (String[] args) { } } class Father { public void fly () { int i = 0 ; System.out.println("Father fly..." ); } public void say () {} } class Son extends Father { @Override public void fly () { System.out.println("Son fly...." ); } @Override public void say () {} }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Deprecated_ { public static void main (String[] args) { A a = new A (); } } @Deprecated class A { public int n1 = 10 ; public void hi () { } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import java.util .ArrayList ;import java.util .List ;@SuppressWarnings ({"rawtypes" , "unchecked" , "unused" }) public class SuppressWarnings_ { public static void main (String [] args ) { List list = new ArrayList (); list.add ("jack" ); list.add ("tom" ); list.add ("mary" ); int i; System .out .println (list.get (1 )); } public void f1 ( ) { List list = new ArrayList (); list.add ("jack" ); list.add ("tom" ); list.add ("mary" ); int i; System .out .println (list.get (1 )); } }
元注解 1) Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME 2) Target // 指定注解可以在哪些地方使用 3) Documented //指定该注解是否会在 javadoc 体现 4) Inherited //子类会继承父类注解
@Retention 的三种值
1)RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注解。
2)RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。
3)RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注解。
异常 基本概念 Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常
执行过程中所发生的异常事件可分为两大类
1) Error(错误):Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError[栈溢出]和OOM(out of memory). Error是严重错误,程序会崩溃。 2) Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等,Exception 分为两大类:运行时异常[程序运行时,发生的异常]和编译时异常[编程时,编译器检查出的异常]。
运行时异常 常见的运行时异常包括
1) NullPointerException 空指针异常 2) ArithmeticException 数学运算异常 3) ArrayIndexOutOfBoundsException 数组下标越界异常 4) ClassCastException 类型转换异常 5) NumberFormatException 数字格式不正确异常
编译时异常 编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译。
SQLException //操作数据库时,查询表可能发生异常
IOException //操作文件时,发生的异常
FileNotFoundException //当操作一个不存在的文件时,发生异常
ClassNotFoundException //加载类,而该类不存在时,异常
EOFException//操作文件,到文件未尾,发生异常
IllegalArguementException //参数异常
异常处理 异常处理就是当异常发生时,对异常处理的方式。
try-catch-finally 程序员在代码中捕获发生的异常,自行处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class TryCatch01 { public static void main (String[] args) { try { String str = "JAVA学习" ; int a = Integer.parseInt(str); System.out.println("数字:" + a); } catch (NumberFormatException e) { System.out.println("异常信息=" + e.getMessage()); } finally { System.out.println("finally 代码块被执行..." ); } System.out.println("程序继续..." ); } }
可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),如果发生异常,只会匹配一个catch。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class TryCatch02 { public static void main (String[] args) { try { Person person = new Person (); person = null ; System.out.println(person.getName()); int n1 = 10 ; int n2 = 0 ; int res = n1 / n2; } catch (NullPointerException e) { System.out.println("空指针异常=" + e.getMessage()); } catch (ArithmeticException e) { System.out.println("算术异常=" + e.getMessage()); } catch (Exception e) { System.out.println(e.getMessage()); } finally { } } } class Person { private String name = "jack" ; public String getName () { return name; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class TryCatchExercise03 {} class ExceptionExe01 { public static int method () { int i = 1 ; try { i++; String[] names = new String [3 ]; if (names[1 ].equals("tom" )) { System.out.println(names[1 ]); } else { names[3 ] = "hspedu" ; } return 1 ; } catch (ArrayIndexOutOfBoundsException e) { return 2 ; } catch (NullPointerException e) { return ++i; } finally { ++i; System.out.println("i=" + i); } } public static void main (String[] args) { System.out.println(method()); } }
catch可以省略,try的形式有三种:
try-catch
try-finally
try-catch-finally
但catch和finally语句不能同时省略!
throws 将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM。
1)如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。 2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import java.io.FileInputStream;import java.io.FileNotFoundException;public class Throws01 { public static void main (String[] args) { f2(); } public static void f2 () { int n1 = 10 ; int n2 = 0 ; double res = n1 / n2; } public static void f1 () throws FileNotFoundException { f3(); } public static void f3 () throws FileNotFoundException { FileInputStream fis = new FileInputStream ("d://aa.txt" ); } public static void f4 () { f5(); } public static void f5 () throws ArithmeticException { } } class Father { public void method () throws RuntimeException { } } class Son extends Father { @Override public void method () throws ArithmeticException { } }
自定义异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class CustomException { public static void main (String[] args) { int age = 180 ; if (!(age >= 18 && age <= 120 )) { throw new AgeException ("年龄需要在 18~120之间" ); } System.out.println("你的年龄范围正确." ); } } class AgeException extends RuntimeException { public AgeException (String message) { super (message); } }
常用类 包装类 1) 针对八种基本数据类型相应的引用类型—包装类
2) 有了类的特点,就可以调用类中的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Wrapper01 { public static void main (String[] args) { Integer i = 100 ; String str1 = i + "" ; String str2 = i.toString(); String str3 = String.valueOf(i); String str4 = "12345" ; Integer i2 = Integer.parseInt(str4); Integer i3 = new Integer (str4); System.out.println("ok~~" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 public class WrapperMethod { public static void main (String[] args) { System.out.println(Integer.MIN_VALUE); System.out.println(Integer.MAX_VALUE); System.out.println(Character.isDigit('a' )); System.out.println(Character.isLetter('a' )); System.out.println(Character.isUpperCase('a' )); System.out.println(Character.isLowerCase('a' )); System.out.println(Character.isWhitespace('a' )); System.out.println(Character.toUpperCase('a' )); System.out.println(Character.toLowerCase('A' )); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Wrapper02 { public static void main (String[] args) { Integer i = new Integer (1 ); Integer j = new Integer (1 ); System.out.println(i == j); Integer m = 1 ; Integer n = 1 ; System.out.println(m == n); Integer x = 128 ; Integer y = 128 ; System.out.println(x == y); } }
String 两种创建 String 对象的区别
方式一:直接赋值String s = “Java”;
方式二:调用构造器String s2 = new String(“Java”);
1.方式一:先从常量池查看是否有”Java”数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。
2.方式二:先在堆中创建空间,里面维护了value属性,指向常量池的Java空间。如果常量池没有””Java””,重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class String01 { public static void main (String[] args) { String a = "study" ; String b = new String ("study" ); System.out.println(a.equals(b)); System.out.println(a==b); System.out.println(a==b.intern()); System.out.println(b==b.intern()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class String01 { public static void main (String[] args) { String a = "study" ; String b = new String ("study" ); System.out.println(a.equals(b)); System.out.println(a == b); System.out.println(a == b.intern()); System.out.println(b == b.intern()); String s = "good " + "evening" ; String s1 = "haha" ; s1 = "hello" ; String s2 = "world" ; String s3 = s1 + s2; Test01 ex = new Test01 (); ex.change(ex.str,ex.ch); System.out.println(ex.str+"and" ); System.out.println(ex.ch); } } class Test01 { String str = new String ("hello" ); final char [] ch = {'j' ,'a' ,'v' ,'a' }; public void change (String str,char [] ch) { str = "java" ; System.out.println(str); ch[0 ]='h' ; } }
String常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public static void main (String[] args) { String str1 = "hello" ; String str2 = "Hello" ; System.out.println(str1.equals(str2)); String username = "johN" ; if ("john" .equalsIgnoreCase(username)) { System.out.println("Success!" ); } else { System.out.println("Failure!" ); } System.out.println("早上好" .length()); String s1 = "wer@terwe@g" ; int index = s1.indexOf('@' ); System.out.println(index); System.out.println("weIndex=" + s1.indexOf("we" )); s1 = "wer@terwe@g@" ; index = s1.lastIndexOf('@' ); System.out.println(index); System.out.println("ter的位置=" + s1.lastIndexOf("ter" )); String name = "hello,张三" ; System.out.println(name.substring(6 )); System.out.println(name.substring(2 ,5 )); } }
由于replaceAll方法的第一个参数是一个正则表达式,而”.”在正则表达式中表示任何字符,所以会把前面字符串的所有字符都替换成”/“。如果想替换的只是”.”,要写成”\.”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 public class String03 { public static void main (String[] args) { String s = "heLLo" ; System.out.println(s.toUpperCase()); System.out.println(s.toLowerCase()); String s1 = "宝玉" ; s1 = s1.concat("林黛玉" ).concat("薛宝钗" ).concat("together" ); System.out.println(s1); s1 = "宝玉 and 林黛玉 林黛玉 林黛玉" ; String s11 = s1.replace("宝玉" , "jack" ); System.out.println(s1); System.out.println(s11); String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦" ; String[] split = poem.split("," ); poem = "E:\\aaa\\bbb" ; split = poem.split("\\\\" ); System.out.println("==分割后内容===" ); for (int i = 0 ; i < split.length; i++) { System.out.println(split[i]); } s = "happy" ; char [] chs = s.toCharArray(); for (int i = 0 ; i < chs.length; i++) { System.out.println(chs[i]); } String a = "jcck" ; String b = "jack" ; System.out.println(a.compareTo(b)); String name = "john" ; int age = 10 ; double score = 56.857 ; char gender = '男' ; String info = "我的姓名是" + name + "年龄是" + age + ",成绩是" + score + "性别是" + gender + "。希望大家喜欢我!" ; System.out.println(info); String formatStr = "我的姓名是%s 年龄是%d,成绩是%.2f 性别是%c.希望大家喜欢我!" ; String info2 = String.format(formatStr, name, age, score, gender); System.out.println("info2=" + info2); } }
StringBuffer类 1) String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低//private final char valuell; 2) StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率较高//char[] value;//这个放在堆.
StringBuffer和String的转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class StringAndStringBuffer { public static void main (String[] args) { String str = "hello tom" ; StringBuffer stringBuffer = new StringBuffer (str); StringBuffer stringBuffer1 = new StringBuffer (); stringBuffer1 = stringBuffer1.append(str); StringBuffer stringBuffer3 = new StringBuffer ("Java学习" ); String s = stringBuffer3.toString(); String s1 = new String (stringBuffer3); } }
StringBuilder类 1)一个可变的字符序列。此类提供一个与StringBuffer 兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作 StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer要快。
2)在 StringBuilder 上的主要操作是append和 insert方法,可重载这些方法,以接受任意类型的数据。
比较 1) StringBuilder和 StringBuffer非常类似,均代表可变的字符序列,而且方法也一样 2) String:不可变字符序列,效率低,但是复用率高。 3) StringBuffer:可变字符序列、效率较高(增删)、线程安全,看源码 3) StringBuilder:可变字符序列、效率最高、线程不安全 5) String使用注意说明: string s=”a”;1/创建了一个字符串 s += “b”;//实际上原来的”a”字符串对象已经丢弃了,现在又产生了一个字符串s+”b”(也就是”ab”)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能=>结论:如果我们对String 做大量修改,不要使用String
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class CompareSSS { public static void main (String[] args) { long startTime = 0L ; long endTime = 0L ; StringBuffer buffer = new StringBuffer ("" ); startTime = System.currentTimeMillis(); for (int i = 0 ; i < 80000 ; i++) { buffer.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuffer的执行时间:" + (endTime - startTime)); StringBuilder builder = new StringBuilder ("" ); startTime = System.currentTimeMillis(); for (int i = 0 ; i < 80000 ; i++) { builder.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuilder的执行时间:" + (endTime - startTime)); String text = "" ; startTime = System.currentTimeMillis(); for (int i = 0 ; i < 80000 ; i++) { text = text + i; } endTime = System.currentTimeMillis(); System.out.println("String的执行时间:" + (endTime - startTime)); } }
使用的原则,结论: 1.如果字符串存在大量的修改操作,一般使用StringBuffer 或StringBuilder
2.如果字符串存在大量的修改操作,并在单线程的情况,使用 StringBuilder
3.如果字符串存在大量的修改操作,并在多线程的情况,使用 StringBuffer
4.如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等StringBuilder的方法使用和StringBuffer 一样,不再说.
Math类 Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class MathMethod { public static void main (String[] args) { int abs = Math.abs(-9 ); System.out.println(abs); double pow = Math.pow(2 , 4 ); System.out.println(pow); double ceil = Math.ceil(3.9 ); System.out.println(ceil); double floor = Math.floor(4.001 ); System.out.println(floor); long round = Math.round(5.51 ); System.out.println(round); double sqrt = Math.sqrt(9.0 ); System.out.println(sqrt); for (int i = 0 ; i < 10 ; i++) { System.out.println((int ) (2 + Math.random() * (7 - 2 + 1 ))); } int min = Math.min(1 , 9 ); int max = Math.max(45 , 90 ); System.out.println("min=" + min); System.out.println("max=" + max); } }
Arrays类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import java.util.Arrays;import java.util.Comparator;import java.util.List;public class Arrays01 { public static void main (String[] args) { Integer[] integers = {1 , 20 , 90 }; System.out.println(Arrays.toString(integers)); Integer arr[] = {1 , -1 , 7 , 0 , 89 }; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); Arrays.sort(arr, new Comparator <Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); System.out.println(Arrays.toString(arr)); Integer[] arr2 = {1 , 2 , 90 , 123 , 567 }; int index = Arrays.binarySearch(arr2, 88 ); System.out.println(index); Integer[] newArr = Arrays.copyOf(arr2, arr2.length); System.out.println("==拷贝执行完毕后==" ); System.out.println(Arrays.toString(newArr)); Integer[] num = new Integer []{9 , 3 , 2 }; Arrays.fill(num, 99 ); System.out.println("==num 数组填充后==" ); System.out.println(Arrays.toString(num)); Integer[] arr3 = {1 , 2 , 90 , 123 }; boolean equals = Arrays.equals(arr, arr3); System.out.println("equals=" + equals); List asList = Arrays.asList(2 , 3 , 4 , 5 , 6 , 1 ); System.out.println("asList=" + asList); System.out.println("asList 的运行类型" + asList.getClass()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 package commonClasses.arrays_;import java.util.Arrays;import java.util.Comparator;public class ArrayExercise { public static void main (String[] args) { Book[] books = new Book [4 ]; books[0 ] = new Book ("红楼梦" , 100 ); books[1 ] = new Book ("金瓶梅新" , 90 ); books[2 ] = new Book ("青年文摘 20 年" , 5 ); books[3 ] = new Book ("java 从入门到放弃~" , 300 ); Arrays.sort(books, new Comparator <Book>() { @Override public int compare (Book o1, Book o2) { return o2.getName().length() - o1.getName().length(); } }); System.out.println(Arrays.toString(books)); } } class Book { String name; double price; public Book () { } public Book (String name, double price) { this .name = name; this .price = price; } public String getName () { return name; } public void setName (String name) { this .name = name; } public double getPrice () { return price; } public void setPrice (double price) { this .price = price; } public String toString () { return "Book{name = " + name + ", price = " + price + "}" ; } }
System类 1)exit 退出当前程序
2)arraycopy:复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组. int[] src={1,2,33}; int[] dest = new int[3]; System.arraycopy(src,0, dest, 0.3);
3)currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
4)gc:运行垃圾回收机制System.gco;
大数据类 BigInteger类 Biglnteger适合保存比较大的整型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.math.BigInteger;public class BigInteger_ { public static void main (String[] args) { BigInteger bigInteger = new BigInteger ("23788888899999999999999999999" ); BigInteger bigInteger2 = new BigInteger ("10099999999999999999999999999999999999999999999999999999999999999999999999999999999" ); System.out.println(bigInteger); BigInteger add = bigInteger.add(bigInteger2); System.out.println(add); BigInteger subtract = bigInteger.subtract(bigInteger2); System.out.println(subtract); BigInteger multiply = bigInteger.multiply(bigInteger2); System.out.println(multiply); BigInteger divide = bigInteger.divide(bigInteger2); System.out.println(divide); } }
BigDecimal BigDecimal适合保存精度更高的浮点型(小数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.math.BigDecimal;public class BigDecimal_ { public static void main (String[] args) { BigDecimal bigDecimal = new BigDecimal ("1999.11" ); BigDecimal bigDecimal2 = new BigDecimal ("3" ); System.out.println(bigDecimal); System.out.println(bigDecimal.add(bigDecimal2)); System.out.println(bigDecimal.subtract(bigDecimal2)); System.out.println(bigDecimal.multiply(bigDecimal2)); System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING)); } }
日期类 第一代日期类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class Date01 { public static void main (String[] args) throws ParseException { Date d1 = new Date (); System.out.println("当前日期=" + d1); Date d2 = new Date (9234567 ); System.out.println("d2=" + d2); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy年MM月dd日 hh:mm:ss E" ); String format = sdf.format(d1); System.out.println("当前日期=" + format); String s = "1996年01月01日 10:20:30 星期一" ; Date parse = sdf.parse(s); System.out.println("parse=" + sdf.format(parse)); } }
第二代日期类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.util.Calendar;public class Calender_ { public static void main (String[] args) { Calendar c = Calendar.getInstance(); System.out.println("c=" + c); System.out.println("年:" + c.get(Calendar.YEAR)); System.out.println("月:" + (c.get(Calendar.MONTH) + 1 )); System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH)); System.out.println("小时:" + c.get(Calendar.HOUR)); System.out.println("分钟:" + c.get(Calendar.MINUTE)); System.out.println("秒:" + c.get(Calendar.SECOND)); System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1 ) + "-" + c.get(Calendar.DAY_OF_MONTH) + " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND) ); } }
第三代日期类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import java.time.LocalDate;import java.time.LocalDateTime;import java.time.LocalTime;import java.time.format.DateTimeFormatter;public class LocalDate_ { public static void main (String[] args) { LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" ); String format = dateTimeFormatter.format(ldt); System.out.println("格式化的日期=" + format); System.out.println("年=" + ldt.getYear()); System.out.println("月=" + ldt.getMonth()); System.out.println("月=" + ldt.getMonthValue()); System.out.println("日=" + ldt.getDayOfMonth()); System.out.println("时=" + ldt.getHour()); System.out.println("分=" + ldt.getMinute()); System.out.println("秒=" + ldt.getSecond()); LocalDate now = LocalDate.now(); LocalTime now2 = LocalTime.now(); LocalDateTime localDateTime = ldt.plusDays(890 ); System.out.println("890 天后=" + dateTimeFormatter.format(localDateTime)); LocalDateTime localDateTime2 = ldt.minusMinutes(3456 ); System.out.println("3456 分钟前 日期=" + dateTimeFormatter.format(localDateTime2)); } }
练习题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package commonClasses.homework;public class Homework01 { public static void main (String[] args) { String str = "abcdef" ; System.out.println("===交换前===" ); System.out.println(str); try { str = reverse(str, 1 , 4 ); } catch (Exception e) { System.out.println(e.getMessage()); return ; } System.out.println("===交换后===" ); System.out.println(str); } public static String reverse (String str, int start, int end) { if (!(str != null && start >= 0 && end > start && end < str.length())) { throw new RuntimeException ("参数不正确" ); } char [] ch = str.toCharArray(); char temp; while (start < end) { temp = ch[start]; ch[start] = ch[end]; ch[end] = temp; start++; end--; } return new String (ch); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Homework02 { public static void main (String[] args) { try { userRegister("fzy" , "789565" , "154@qq.com" ); } catch (Exception e) { System.out.println(e.getMessage()); System.out.println("注册失败" ); return ; } System.out.println("注册成功" ); } public static void userRegister (String name, String pwd, String email) { if (name.length() < 2 || name.length() > 4 ) { throw new RuntimeException ("用户名长度必须为2-4" ); } if (!(pwd.length() == 6 && isDigital(pwd))) { throw new RuntimeException ("密码要求长度为6,且全为数字" ); } else { } if (!(email.indexOf('@' ) > 0 && email.indexOf('@' ) < email.indexOf('.' ))) { throw new RuntimeException ("邮箱格式不正确," ); } } public static boolean isDigital (String str) { char [] ch = str.toCharArray(); for (int i = 0 ; i < ch.length; i++) { if (ch[i] < '0' || ch[i] > '9' ) { return false ; } } return true ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class Homework03 { public static void main (String[] args) { printName("Feng zhui Yu" ); } public static void printName (String str) { if (str == null ) { System.out.println("str is null" ); return ; } String[] strArray = str.split(" " ); if (strArray.length != 3 ) { System.out.println("格式不正确" ); return ; } String infoStr = String.format("%s,%s .%c" , strArray[2 ], strArray[0 ], strArray[1 ].toUpperCase().charAt(0 )); System.out.println(infoStr); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class Homework04 { public static void main (String[] args) { String str = "abcHsp U 1234" ; countStr(str); } public static void countStr (String str) { if (str == null ) { System.out.println("输入不能为 null" ); return ; } int strLen = str.length(); int numCount = 0 ; int lowerCount = 0 ; int upperCount = 0 ; int otherCount = 0 ; for (int i = 0 ; i < strLen; i++) { if (str.charAt(i) >= '0' && str.charAt(i) <= '9' ) { numCount++; } else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z' ) { lowerCount++; } else if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z' ) { upperCount++; } else { otherCount++; } } System.out.println("数字有 " + numCount); System.out.println("小写字母有 " + lowerCount); System.out.println("大写字母有 " + upperCount); System.out.println("其他字符有 " + otherCount); } }
集合 单列集合
双列集合
Collection接口 public interface Collection extends lterable
1)collection实现子类可以存放多个元素,每个元素可以是Object
2)有些Collection的实现类,可以存放重复的元素,有些不可以
3)有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
4)Collection接口没有直接的实现子类,是通过它的子接口Set 和 List来实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.util.ArrayList;import java.util.List;public class CollectionMethod { public static void main (String[] args) { List list = new ArrayList (); list.add("jack" ); list.add(10 ); list.add(true ); System.out.println("list=" + list); list.remove(true ); System.out.println("list=" + list); System.out.println(list.contains("jack" )); System.out.println(list.size()); System.out.println(list.isEmpty()); list.clear(); System.out.println("list=" + list); ArrayList list2 = new ArrayList (); list2.add("红楼梦" ); list2.add("三国演义" ); list.addAll(list2); System.out.println("list=" + list); System.out.println(list.containsAll(list2)); list.add("聊斋" ); list.removeAll(list2); System.out.println("list=" + list); } }
1)Iterator迭代器
2)for循环增强
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class CollectionExercise { public static void main (String[] args) { List list = new ArrayList (); list.add(new Dog ("小黑" , 3 )); list.add(new Dog ("大黄" , 100 )); list.add(new Dog ("大壮" , 8 )); System.out.println("使用Iterator" ); Iterator iterator = list.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); System.out.println(next); } System.out.println("使用增强for" ); for (Object dog : list) { System.out.println(dog); } } } class Dog { private String name; private int age; public Dog (String name, int age) { this .name = name; this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public String toString () { return "Dog{name = " + name + ", age = " + age + "}" ; } }
List接口 List 接口是 Collection接口的子接口 1) List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 2) List集合中的每个元素都有其对应的顺序索引,即支持索引。 1) List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根 据序号存取容器中的元素。
常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import java.util.ArrayList;import java.util.List;public class ListMethod { public static void main (String[] args) { List list = new ArrayList (); list.add("张三丰" ); list.add("贾宝玉" ); list.add(1 , "Java" ); System.out.println("list=" + list); List list2 = new ArrayList (); list2.add("jack" ); list2.add("tom" ); list.addAll(1 , list2); System.out.println("list=" + list); System.out.println(list.indexOf("tom" )); list.add("Java" ); System.out.println("list=" + list); System.out.println(list.lastIndexOf("Java" )); list.remove(0 ); System.out.println("list=" + list); System.out.println("list=" + list); List returnlist = list.subList(0 , 2 ); System.out.println("returnlist=" + returnlist); } }
ArrayList 1)ArrayList中维护了一个Object类型的数组elementData transient Object[ elementData;//transient表示瞬间,短暂的,表示该属性不会被序列化。
2)当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容, 则直接扩容elementData为1.5倍。
Vector 1) Vector类的定义说明 public class vectorextends AbstractList implements List,RandomAccess,cloneable,Serializable 2) Vector底层也是一个对象数组,protected objectl[]elementData; 3) Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronizedpublic synchronized E get(int index){ if (index >= elementCount) throw new ArraylndexOutOfBoundsException(index);return elementData(index); } 4) 在开发中,需要线程同步安全时,考虑使用Vector
LinkedList 1)LinkedList底层实现了双向链表和双端队列特点
2)可以添加任意元素(元素可以重复),包括null
3)线程不安全,没有实现同步
1)LinkedList底层维护了一个双向链表.
2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点
3)每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表
4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
Set接口 同Collection的遍历方式一样,因为Set接口是Collection接口的子接口。
1.可以使用迭代器
2.增强for
3.不能使用索引的方式来获取
HashSet 1)HashSet实现了Set接口
2)HashSet实际上是HashMap
3)可以存放null值,但是只能有一个null
4)HashSet不保证元素是有序的,取决于hash后,再确定索引的结果.(即,不保证存放元素的顺序和取出顺序一致)
5)不能有重复元泰/对象
分析HashSet的添加元素底层是如何实现(hash()+equals())
HashSet底层是 HashMap
添加一个元素时,先得到hash值-会转成->索引值
找到存储数据表table,看这个索引位置是否已经存放的有元素,如果没有,直接加入 。如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则添加到最后
在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(就认是8),并且table的大小>=MIN TREEIFY CAPACITY(默认64)。就会进行树化(红黑树)
HashSet底层是HashMap,第一次添加时,table数组扩容到16,临界值(threshold)是1加载因子(loadFactor)是0.75=12
如果table数组使用到了临界值12,就会扩容到162=32,新的临界值就是32\ 0.75 =24,依次类推
在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8).并且table的大小>=MIN TREEIFY CAPACITY(默认64).就会进行树化(红黑树),否则仍然采用数组扩容机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 import java.util.HashSet;import java.util.Objects;public class HashSet01 { public static void main (String[] args) { HashSet hs = new HashSet (); hs.add(new Employee ("tom" , 12000 , new MyDate (2000 , 1 , 1 ))); hs.add(new Employee ("tom" , 12000 , new MyDate (2000 , 1 , 1 ))); hs.add(new Employee ("tom" , 8000 , new MyDate (2000 , 1 , 1 ))); hs.add(new Employee ("bob" , 12000 , new MyDate (2000 , 1 , 1 ))); hs.add(new Employee ("tom" , 12000 , new MyDate (1999 , 1 , 1 ))); System.out.println(hs); } } class Employee { private String name; private double salary; MyDate birthday; public Employee () { } public Employee (String name, double salary, MyDate birthday) { this .name = name; this .salary = salary; this .birthday = birthday; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Employee employee = (Employee) o; return Objects.equals(name, employee.name) && Objects.equals(birthday, employee.birthday); } @Override public int hashCode () { return Objects.hash(name, birthday); } public String getName () { return name; } public void setName (String name) { this .name = name; } public double getSalary () { return salary; } public void setSalary (double salary) { this .salary = salary; } public MyDate getBirthday () { return birthday; } public void setBirthday (MyDate birthday) { this .birthday = birthday; } public String toString () { return "\nEmployee{name = " + name + ", salary = " + salary + ", birthday = " + birthday + "}" ; } } class MyDate { private int year; private int month; private int day; public MyDate (int year, int month, int day) { this .year = year; this .month = month; this .day = day; } public int getYear () { return year; } public void setYear (int year) { this .year = year; } public int getMonth () { return month; } public void setMonth (int month) { this .month = month; } public int getDay () { return day; } public void setDay (int day) { this .day = day; } @Override public String toString () { return year + "-" + month + "-" + day; } @Override public boolean equals (Object o) { if (this == o) { return true ; } if (o == null || getClass() != o.getClass()) { return false ; } MyDate myDate = (MyDate) o; return year = = myDate.year && month == myDate.month && day == myDate.day; } @Override public int hashCode () { return Objects.hash(year, month, day); } }
LinkedHashSet 1) LinkedHashSet是 HashSet的子类 2) LinkedHashSet底层是一个 LinkedHashMap,底层维护了一个数组+双向链表 3) LinkedHashSet根据元素的 hashCode值来决定元素的存储位置,同时使用链表维护元素的次序(图),这使得元素看起来是以插入顺序保存的。 4) LinkedHashSet不允许添重复元素
TreeSet 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.util.Comparator;import java.util.TreeSet;public class TreeSet_ { public static void main (String[] args) { TreeSet t = new TreeSet (new Comparator () { @Override public int compare (Object o1, Object o2) { return ((String) o1).length() - ((String) o2).length(); } }); t.add("Jack" ); t.add("Bob" ); t.add("Hello" ); t.add("Mary" ); System.out.println(t); } }
Map接口
Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value
Map 中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
Map中的key不允许重复,当有相同的k时,会替换v
Map 中的value可以重复
Map 的key 可以为null, value也可以为null,注意key 为null,只能有一个,value为null ,可以多个
常用String类作为Map的key
key 和value 之间存在单向一对一关系,即通过指定的key总能找到对应的value
put:添加对象
remove:根据键删除映射关系
get:根据键获取值
size:获取元素个数
isEmpty:判断个数是否为
clear:清除 k-v
containsKey:查找键是否存在
1)containsKey:查找键是否存在
2)keySet:获取所有的键
3)entrySet:获取所有关系k-v
4)values:获取所有的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 import java.util.*;public class MapExercise { public static void main (String[] args) { Person person1 = new Person (1 , "John" , 20000 ); Person person2 = new Person (2 , "Bob" , 15000 ); Person person3 = new Person (3 , "Mary" , 25000 ); HashMap hashMap = new HashMap (); hashMap.put(person1.getId(), person1); hashMap.put(person2.getId(), person2); hashMap.put(person3.getId(), person3); System.out.println("第一组" ); Set keySet = hashMap.keySet(); for (Object key : keySet) { if (((Person)hashMap.get(key)).getSalary()>18000 ){ System.out.println(hashMap.get(key)); } } Iterator iterator1 = keySet.iterator(); while (iterator1.hasNext()) { Object next = iterator1.next(); if (((Person)hashMap.get(next)).getSalary()>18000 ){ System.out.println(hashMap.get(next)); } } System.out.println("第二组" ); Collection values = hashMap.values(); for (Object value : values){ if (((Person)value).getSalary()>18000 ){ System.out.println(value); } } Iterator iterator2 = values.iterator(); while (iterator2.hasNext()) { Object next = iterator2.next(); if (((Person)next).getSalary()>18000 ){ System.out.println(next); } } System.out.println("第三组" ); Set entrySet = hashMap.entrySet(); for (Object entry : entrySet){ Map.Entry m = (Map.Entry) entry; if (((Person)m.getValue()).getSalary()>18000 ){ System.out.println(m.getValue()); } } Iterator iterator3 = entrySet.iterator(); while (iterator3.hasNext()) { Map.Entry m = (Map.Entry) iterator3.next(); if (((Person)m.getValue()).getSalary()>18000 ){ System.out.println(m.getValue()); } } } } class Person { private int id; private String name; private double salary; public Person () { } public Person (int id, String name, double salary) { this .id = id; this .name = name; this .salary = salary; } public int getId () { return id; } public void setId (int id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public double getSalary () { return salary; } public void setSalary (double salary) { this .salary = salary; } public String toString () { return "Person{id = " + id + ", name = " + name + ", salary = " + salary + "}" ; } }
HashMap 1) Map接口的常用实现类:HashMap、Hashtable和Properties. 2) HashMap是 Map接口使用频率最高的实现类。 3) HashMap是以 key-val对的方式来存储数据(HashMap$Node类型) 4) key不能重复,但是值可以重复,允许使用null键和null值。 5) 如果添加相同的key,则会覆盖原来的key-val ,等同于修改.(key不会替换,val会替换) 6) 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.(jdk8的hashMap底层数组+链表+红黑树) 7) HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有 synchronized 8) 扩容机制与HashSet一致
HashTable
存放的元素是键值对:即K-V
hashtable的键和值都不能为null,否则会抛出NullPointerException
hashTable使用方法基本上和HashMap一样
hashTable是线程安全的(synchronized). hashMap是线程不安全的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import java.util.Properties;public class Properties_ { public static void main (String[] args) { Properties properties = new Properties (); properties.put("john" , 100 ); properties.put("lucy" , 100 ); properties.put("lic" , 100 ); properties.put("lic" , 88 ); System.out.println("properties=" + properties); System.out.println(properties.get("lic" )); properties.remove("lic" ); System.out.println("properties=" + properties); properties.put("john" , "约翰" ); System.out.println("properties=" + properties); } }
Properties
Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形 式来保存数据。
使用特点和Hashtable类似
Properties还可以用于从xxx.properties 文件中,加载数据到Properties类对象, 并进行读取和修改
xxx.properties文件通常作为配置文件
TreeMap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.Comparator;import java.util.TreeMap;public class TreeMap_ { public static void main (String[] args) { TreeMap treeMap = new TreeMap (new Comparator () { @Override public int compare (Object o1, Object o2) { return ((String) o2).length() - ((String) o1).length(); } }); treeMap.put("jack" , "杰克" ); treeMap.put("tom" , "汤姆" ); treeMap.put("kristina" , "克瑞斯提诺" ); treeMap.put("smith" , "斯密斯" ); treeMap.put("bob" , "鲍勃" ); System.out.println("treemap=" + treeMap); } }
Collections工具类 1) Collections是一个操作 Set、List 和 Map等集合的工具类 2) Collections中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作
排序 1) reverse(List):反转List中元素的顺序 2) shuffle(List):对List集合元素进行随机排序 3) sort(List):根据元素的自然顺序对指定List集合元素按升序排序 4) sort(List,Comparator):根据指定的Comparator产生的顺序对 List集合元素进行排序 5) swap(List,int i,int j):将指定 list集合中的i处元素和j处元素进行交换
查找、替换 1) Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素 2) object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素 3) Object min(Collection) 4) Object min(Collection, Comparator) 5) int frequency(Collection,object):返回指定集合中指定元素的出现次数 5) void copy(List dest,List src):将src中的内容复制到dest中 7) boolean replaceAll(List list,Object oldval,Object newVal):使用新值替换List 对象的所有旧值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;public class Collections_ { public static void main (String[] args) { List list = new ArrayList (); list.add("tom" ); list.add("smith" ); list.add("king" ); list.add("milan" ); list.add("tom" ); Collections.reverse(list); System.out.println("list=" + list); Collections.sort(list); System.out.println("自然排序后" ); System.out.println("list=" + list); Collections.sort(list, new Comparator () { @Override public int compare (Object o1, Object o2) { return ((String) o2).length() - ((String) o1).length(); } }); System.out.println("字符串长度大小排序=" + list); Collections.swap(list, 0 , 1 ); System.out.println("交换后的情况" ); System.out.println("list=" + list); System.out.println("自然顺序最大元素=" + Collections.max(list)); Object maxObject = Collections.max(list, new Comparator () { @Override public int compare (Object o1, Object o2) { return ((String) o1).length() - ((String) o2).length(); } }); System.out.println("长度最大的元素=" + maxObject); System.out.println("tom出现的次数=" + Collections.frequency(list, "tom" )); ArrayList dest = new ArrayList (); for (int i = 0 ; i < list.size(); i++) { dest.add("" ); } Collections.copy(dest, list); System.out.println("dest=" + dest); Collections.replaceAll(list, "tom" , "汤姆" ); System.out.println("list替换后=" + list); } }
小结
练习题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import java.util.ArrayList;public class Homework01 { public static void main (String[] args) { ArrayList arrayList = new ArrayList (); arrayList.add(new News ("新冠确诊病例超千万,数百万印度教信徒赴恒河“圣浴”引民众担忧" )); arrayList.add(new News ("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生" )); arrayList.add(new News ("樱花树下你和我" )); for (int i = arrayList.size() - 1 ; i >= 0 ; i--) { String title = ((News) (arrayList.get(i))).getTitle(); if (title.length() <= 15 ) { System.out.println(title); } else { title = title.substring(0 , 15 ); title += "..." ; System.out.println(title); } } } } class News { private String title; private String description; public News (String title) { this .title = title; } public String getTitle () { return title; } public void setTitle (String title) { this .title = title; } public String getDescription () { return description; } public void setDescription (String description) { this .description = description; } @Override public String toString () { return "News{" + "title='" + title + '\'' + '}' ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import java.util.*;public class Homework03 { public static void main (String[] args) { HashMap hashMap = new HashMap (); hashMap.put("jack" , 650 ); hashMap.put("tom" , 1200 ); hashMap.put("smith" , 2900 ); System.out.println(hashMap); hashMap.put("jack" , 2600 ); System.out.println(hashMap); for (Object key : hashMap.keySet()) { hashMap.put(key, (Integer) hashMap.get(key) + 100 ); } System.out.println("=============遍历=============" ); Set entrySet = hashMap.entrySet(); Iterator iterator = entrySet.iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); System.out.println(entry.getKey() + "-" + entry.getValue()); } System.out.println("====遍历所有的工资====" ); Collection values = hashMap.values(); for (Object value : values) { System.out.println(value); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import java.util.HashSet;import java.util.Objects;public class Homework06 { public static void main (String[] args) { HashSet set = new HashSet (); Person p1 = new Person (1001 ,"AA" ); Person p2 = new Person (1002 ,"BB" ); set.add(p1); set.add(p2); p1.name = "CC" ; set.remove(p1); System.out.println(set); set.add(new Person (1001 ,"CC" )); System.out.println(set); set.add(new Person (1001 ,"AA" )); System.out.println(set); } } class Person { public String name; public int id; public Person (int id, String name) { this .name = name; this .id = id; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Person person = (Person) o; return id = = person.id && Objects.equals(name, person.name); } @Override public int hashCode () { return Objects.hash(name, id); } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", id=" + id + '}' ; } }
泛型 1)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
2)在类声明或实例化时只要指定好需要的具体的类型即可。
3)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
4)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 import java.util.*;public class GenericExercise { public static void main (String[] args) { HashSet<Student> students = new HashSet <Student>(); students.add(new Student ("jack" , 18 )); students.add(new Student ("tom" , 28 )); students.add(new Student ("mary" , 19 )); for (Student student : students) { System.out.println(student); } HashMap<String, Student> hm = new HashMap <String, Student>(); hm.put("milan" , new Student ("milan" , 38 )); hm.put("smith" , new Student ("smith" , 48 )); hm.put("bob" , new Student ("bob" , 28 )); Set<Map.Entry<String, Student>> entries = hm.entrySet(); Iterator<Map.Entry<String, Student>> iterator = entries.iterator(); while (iterator.hasNext()) { Map.Entry<String, Student> next = iterator.next(); System.out.println(next.getKey() + "-" + next.getValue()); } } } class Student { private String name; private int age; public Student (String name, int age) { this .name = name; this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public String toString () { return "Student{name = " + name + ", age = " + age + "}" ; } }
interface List\{},public class HashSet\{}..等等 说明:T,E只能是引用类型
在给泛型指定具体类型后,可以传入该类型或者其子类类型
.泛型使用形式 List\ list1 = new ArrayList\{}:
List\ list2 = new ArrayList<>{};//推荐
如果我们这样写List list3 = new ArrayList();默认给它的泛型是[\ E就是Object ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 import java.util.ArrayList;import java.util.Comparator;public class GenericExercise02 { public static void main (String[] args) { ArrayList<Employee> employees = new ArrayList <>(); employees.add(new Employee ("tom" , 20000 , new MyDate (1980 , 12 , 11 ))); employees.add(new Employee ("jack" , 12000 , new MyDate (2001 , 12 , 12 ))); employees.add(new Employee ("tom" , 50000 , new MyDate (1980 , 12 , 10 ))); System.out.println(employees); employees.sort(new Comparator <Employee>() { @Override public int compare (Employee emp1, Employee emp2) { if (!(emp1 instanceof Employee && emp2 instanceof Employee)) { System.out.println("类型不正确" ); return 0 ; } int i = emp1.getName().compareTo(emp2.getName()); if (i != 0 ) { return i; } return emp1.getBirthday().compareTo(emp2.getBirthday()); } }); System.out.println(employees); } } class MyDate { private int year; private int month; private int day; public MyDate (int year, int month, int day) { this .year = year; this .month = month; this .day = day; } public int getYear () { return year; } public void setYear (int year) { this .year = year; } public int getMonth () { return month; } public void setMonth (int month) { this .month = month; } public int getDay () { return day; } public void setDay (int day) { this .day = day; } public String toString () { return "MyDate{year = " + year + ", month = " + month + ", day = " + day + "}" ; } public int compareTo (MyDate o) { if (year != o.year) { return year - o.year; } if (month != o.month) { return month - o.month; } if (day != o.day) { return day - o.day; } return 0 ; } } class Employee { private String name; private double salary; private MyDate birthday; public Employee (String name, double salary, MyDate birthday) { this .name = name; this .salary = salary; this .birthday = birthday; } public String getName () { return name; } public void setName (String name) { this .name = name; } public double getSalary () { return salary; } public void setSalary (double salary) { this .salary = salary; } public MyDate getBirthday () { return birthday; } public void setBirthday (MyDate birthday) { this .birthday = birthday; } @Override public String toString () { return "\nEmployee{" + "name='" + name + '\'' + ", salary=" + salary + ", birthday=" + birthday + '}' ; } }
自定义泛型 自定义泛型类
class类名{//…表示可以有多个泛型
成员
}
1)普通成员可以使用泛型(属性、方法)
2)使用泛型的数组,不能初始化
3)静态方法中不能使用类的泛型
4)泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
5)如果在创建对象时,没有指定类型,默认为Object
自定义泛型接口
interface接口名{}
1)接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
2)泛型接口的类型,在继承接口或者实现接口时确定
3)没有指定类型,默认为Object
自定义泛型方法
修饰符返回类型方法名(参数列表){
}
1.泛型方法,可以定义在普通类中,也可以定义在泛型类中
2.当泛型方法被调用时,类型会确定
3.public void eat(E e){},修饰符后没有 eat方法不是泛型方法,而是使用了泛型
泛型的继承和通配符
泛型不具备继承性
<?>:支持任意泛型类型
<? extends A>:支持A类以及A类的子类,规定了泛型的上限
<? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 import java.util.ArrayList;import java.util.List;public class GenericExtends { public static void main (String[] args) { Object o = new String ("xx" ); List<Object> list1 = new ArrayList <>(); List<String> list2 = new ArrayList <>(); List<AA> list3 = new ArrayList <>(); List<BB> list4 = new ArrayList <>(); List<CC> list5 = new ArrayList <>(); printCollection1(list1); printCollection1(list2); printCollection1(list3); printCollection1(list4); printCollection1(list5); printCollection2(list3); printCollection2(list4); printCollection2(list5); printCollection3(list1); printCollection3(list3); } public static void printCollection2 (List<? extends AA> c) { for (Object object : c) { System.out.println(object); } } public static void printCollection1 (List<?> c) { for (Object object : c) { System.out.println(object); } } public static void printCollection3 (List<? super AA> c) { for (Object object : c) { System.out.println(object); } } } class AA {} class BB extends AA {} class CC extends BB {}
JUnit 1.一个类有很多功能代码需要测试,为了测试,就需要写入到main方法中
2.如果有多个功能代码测试,就需要来回注销,切换很麻烦
3.如果可以直接运行一个方法,就方便很多,并且可以给出相关信息,就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 import org.junit.jupiter.api.Test;import java.util.*;public class Homework01 { public static void main (String[] args) { } @Test public void testList () { DAO<User> dao = new DAO <>(); dao.save("001" , new User (1 , 10 , "jack" )); dao.save("002" , new User (2 , 18 , "king" )); dao.save("003" , new User (3 , 38 , "smith" )); List<User> list = dao.list(); System.out.println("list=" + list); dao.update("003" , new User (3 , 58 , "milan" )); dao.delete("001" ); System.out.println("===修改后====" ); list = dao.list(); System.out.println("list=" + list); System.out.println("id=003 " + dao.get("003" )); } } class User { private int id; private int age; private String name; public User (int id, int age, String name) { this .id = id; this .age = age; this .name = name; } public int getId () { return id; } public void setId (int id) { this .id = id; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public String toString () { return "User{id = " + id + ", age = " + age + ", name = " + name + "}" ; } } class DAO <T> { private Map<String, T> map = new HashMap <>(); public void save (String id, T entity) { map.put(id, entity); } public T get (String id) { return map.get(id); } public void update (String id, T entity) { map.put(id, entity); } public List<T> list () { List<T> list = new ArrayList <T>(); Set<String> keySet = map.keySet(); for (String key : keySet) { list.add(map.get(key)); } return list; } public void delete (String id) { map.remove(id); } }
Java绘图技术
Component类提供了两个和绘图相关最重要的方法:
paint(Graphics g)绘制组件的外观
repaint()刷新组件的外观。
当组件第一次在屏幕显示的时候,程序会自动的调用paint(方法来绘制组件。
在以下情况paint()将会被调用:
窗口最小化.再最大化
窗口的大小发生变化
repaint方法被调用
Graphics类、可以理解就是画笔,为我们提供了各种绘制图形的方法
画直线drawLine(int x1,int y1,int x2,int y2)
画矩形边框drawRect(int x, int y, int width, int height)
画椭圆边框drawOval(int x, int y, int width, int height)
填充矩形fillRect(int x, int y. int width, int height)
填充椭圆fillOval(int x, int y. int width, int height)
画图片drawlmage(Image img, int x, int y, ..)
画字符串drawString(String str. int x, int y)
设置画笔的字体setFont(Font font)
设置画笔的颜色setColor(Color c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 import javax.swing.*;import java.awt.*; public class DrawCircle extends JFrame { private MyPanel mp = null ; public static void main (String[] args) { new DrawCircle (); System.out.println("退出程序~" ); } public DrawCircle () { mp = new MyPanel (); this .add(mp); this .setSize(400 , 300 ); this .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this .setVisible(true ); } } class MyPanel extends JPanel { @Override public void paint (Graphics g) { super .paint(g); System.out.println("paint 方法被调用了~" ); g.setColor(Color.red); g.setFont(new Font ("隶书" , Font.BOLD, 50 )); g.drawString("北京你好" , 100 , 100 ); } }
事件处理机制 java事件处理是采取”委派事件模型”。当事件发生时,产生事件的对象,会把此”信息”传递给”事件的监听者” 处理,这里所说的“信息”实际上就是java.awt.event事件类库里某个类所创建的对象,把它称为”事件的对象””。
事件源:事件源是一个产生事件的对象,比如按钮,窗口等。
事件:事件就是承载事件源状态改变时的对象,比如当键盘事件、鼠标事件、窗口事件等等,会生成一个事件对象,该对象保存着当前事件很多信息,比如KeyEvent对象有含有被按下键的Code值。java.awt.event包和javax.swing.event包中定义了各种事件类型
事件监听器接口:
(1)当事件源产生一个事件,可以传送给事件监听者处理
(2)事件监听者实际上就是一个类,该类实现了某个事件监听器接口比如前面我们案例申的MyPanle就是一个类,它实现了KeyListener接口,它就可以作为一个事件监听者,对接受到的事件进行处理
(3)事件监听器接口有多种,不同的事件监听器接口可以监听不同的事件,一个类可以实现多个监听接口
(4)这些接口在java.awt.event包和javax.swing.event包中定义.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package tankGame01.event_;import javax.swing.*;import java.awt.*;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;public class BallMove extends JFrame { MyPanel mp = null ; public static void main (String[] args) { BallMove ballMove = new BallMove (); } public BallMove () { mp = new MyPanel (); this .add(mp); this .setSize(400 , 300 ); this .addKeyListener(mp); this .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this .setVisible(true ); } } class MyPanel extends JPanel implements KeyListener { int x = 10 ; int y = 10 ; @Override public void paint (Graphics g) { super .paint(g); g.fillOval(x, y, 20 , 20 ); } @Override public void keyTyped (KeyEvent e) { } @Override public void keyPressed (KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_DOWN) { y++; } else if (e.getKeyCode() == KeyEvent.VK_UP) { y--; } else if (e.getKeyCode() == KeyEvent.VK_LEFT) { x--; } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) { x++; } this .repaint(); } @Override public void keyReleased (KeyEvent e) { } }
多线程基础 1.单线程:同一个时刻,只允许执行一个线程
2.多线程:同一个时刻,可以执行多个线程,比如:一个qq进程,可以同时打开多个聊天窗口,一个迅雷进程,可以同时下载多个文件
3.并发:同一个时刻,多个任务交替执行,造成一种“貌似同时”的错觉,简单的说,单核cpu实现的多任务就是并发。
4.并行:同一个时刻,多个任务同时执行。多核cpu可以实现并行。
线程基本使用 继承 Thread 类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 public class Thread01 { public static void main (String[] args) throws InterruptedException { Cat cat = new Cat (); cat.start(); System.out.println("主线程继续执行" + Thread.currentThread().getName()); for (int i = 0 ; i < 60 ; i++) { System.out.println("主线程 i=" + i); Thread.sleep(1000 ); } } } class Cat extends Thread { int times = 0 ; @Override public void run () { while (true ) { System.out.println("喵喵, 我是小猫咪" + (++times) + " 线程名=" + Thread.currentThread().getName()); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } if (times == 80 ) { break ; } } } }
实现 Runnable 接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public class Thread02 { public static void main (String[] args) { Dog dog = new Dog (); Thread thread = new Thread (dog); thread.start(); } } class Animal {} class Tiger extends Animal implements Runnable { @Override public void run () { System.out.println("老虎嗷嗷叫...." ); } } class ThreadProxy implements Runnable { private Runnable target = null ; @Override public void run () { if (target != null ) { target.run(); } } public ThreadProxy (Runnable target) { this .target = target; } public void start () { start0(); } public void start0 () { run(); } } class Dog implements Runnable { int count = 0 ; @Override public void run () { while (true ) { System.out.println("小狗汪汪叫..hi" + (++count) + Thread.currentThread().getName()); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 10 ) { break ; } } } }
多线程执行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class Thread03 { public static void main (String[] args) { T1 t1 = new T1 (); T2 t2 = new T2 (); Thread thread1 = new Thread (t1); Thread thread2 = new Thread (t2); thread1.start(); thread2.start(); } } class T1 implements Runnable { int count = 0 ; @Override public void run () { while (true ) { System.out.println("hello,world " + (++count)); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 60 ) { break ; } } } } class T2 implements Runnable { int count = 0 ; @Override public void run () { while (true ) { System.out.println("hi " + (++count)); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 50 ) { break ; } } } }
线程终止 1.当线程完成任务后,会自动退出。
2.还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class ThreadExit_ { public static void main (String[] args) throws InterruptedException { T t1 = new T (); t1.start(); System.out.println("main线程休眠10s..." ); Thread.sleep(10 * 1000 ); t1.setLoop(false ); } } class T extends Thread { private int count = 0 ; private boolean loop = true ; @Override public void run () { while (loop) { try { Thread.sleep(50 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("T 运行中...." + (++count)); } } public void setLoop (boolean loop) { this .loop = loop; } }
线程常用方法
注意事项和细节
1.start底层会创建新的线程,调用run,run就是一个简单的方法调用,不会启动新线程
2.线程优先级的范围
3.interrupt,中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠线
4.sleep:线程的静态方法,使当前线程休眠
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class ThreadMethod01 { public static void main (String[] args) throws InterruptedException { T t = new T (); t.setName("老王" ); t.setPriority(Thread.MIN_PRIORITY); t.start(); for (int i = 0 ; i < 5 ; i++) { Thread.sleep(1000 ); System.out.println("hi " + i); } System.out.println(t.getName() + " 线程的优先级 =" + t.getPriority()); t.interrupt(); } } class T extends Thread { @Override public void run () { while (true ) { for (int i = 0 ; i < 100 ; i++) { System.out.println(Thread.currentThread().getName() + " 吃包子~~~~" + i); } try { System.out.println(Thread.currentThread().getName() + " 休眠中~~~" ); Thread.sleep(20000 ); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + "被 interrupt了" ); } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class ThreadMethod02 { public static void main (String[] args) throws InterruptedException { Thread t3 = new Thread (new T3 ()); for (int i = 1 ; i <= 10 ; i++) { System.out.println("hi " + i); if (i == 5 ) { t3.start(); t3.join(); } Thread.sleep(1000 ); } } } class T3 implements Runnable { private int count = 0 ; @Override public void run () { while (true ) { System.out.println("hello " + (++count)); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 10 ) { break ; } } } }
用户线程和守护线程 1.用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
2.守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
3.常见的守护线程:垃圾回收机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class ThreadMethod03 { public static void main (String[] args) throws InterruptedException { MyDaemonThread myDaemonThread = new MyDaemonThread (); myDaemonThread.setDaemon(true ); myDaemonThread.start(); for ( int i = 1 ; i <= 10 ; i++) { System.out.println("A在辛苦的工作..." ); Thread.sleep(1000 ); } } } class MyDaemonThread extends Thread { public void run () { for (; ; ) { try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("B和C快乐聊天,哈哈哈~~~" ); } } }
线程的生命周期 NEW:尚未启动的线程处于此状态。
RUNNABLE:在Java虚拟机中执行的线程处于此状态。
BLOCKED:;被阻塞等待监视器锁定的线程处于此状态。
WAITING:正在等待另一个线程执行特定动作的线程处于此状态。
TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
TERMINATED:已退出的线程处于此状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class ThreadState_ { public static void main (String[] args) throws InterruptedException { T t = new T (); System.out.println(t.getName() + " 状态 " + t.getState()); t.start(); while (Thread.State.TERMINATED != t.getState()) { System.out.println(t.getName() + " 状态 " + t.getState()); Thread.sleep(500 ); } System.out.println(t.getName() + " 状态 " + t.getState()); } } class T extends Thread { @Override public void run () { while (true ) { for (int i = 0 ; i < 10 ; i++) { System.out.println("hi " + i); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } } break ; } } }
线程的同步 Synchronized 1.在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技 术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。
2.也可以这里理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作.
互斥锁 1.Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
2.每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
3.关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问
4.同步的局限性:导致程序的执行效率要降低
5.同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)
6.同步方法(静态的)的锁为当前类本身。
线程的死锁 多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,在编程是一定要避免死锁的发生。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class DeadLock_ { public static void main (String[] args) { DeadLockDemo A = new DeadLockDemo (true ); A.setName("A线程" ); DeadLockDemo B = new DeadLockDemo (false ); B.setName("B线程" ); A.start(); B.start(); } } class DeadLockDemo extends Thread { static Object o1 = new Object (); static Object o2 = new Object (); boolean flag; public DeadLockDemo (boolean flag) { this .flag = flag; } @Override public void run () { if (flag) { synchronized (o1) { System.out.println(Thread.currentThread().getName() + " 进入1" ); synchronized (o2) { System.out.println(Thread.currentThread().getName() + " 进入2" ); } } } else { synchronized (o2) { System.out.println(Thread.currentThread().getName() + " 进入3" ); synchronized (o1) { System.out.println(Thread.currentThread().getName() + " 进入4" ); } } } } }
释放锁
1.当前线程的同步方法、同步代码块执行结束案例
2.当前线程在同步代码块、同步方法中遇到break、return.
3.当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
4.当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。
1.线程执行同步代码块或同步方法时,程序调用Thread.sleep0、Thread.yield()方法暂停当前线程的执行,不会释放锁
2.线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。提示:应尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用
练习题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import java.util.Scanner;public class Homework01 { public static void main (String[] args) { A a = new A (); B b = new B (a); a.start(); b.start(); } } class A extends Thread { private boolean loop = true ; @Override public void run () { while (loop) { System.out.println((int )(Math.random() * 100 + 1 )); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("a线程退出..." ); } public void setLoop (boolean loop) { this .loop = loop; } } class B extends Thread { private A a; private Scanner scanner = new Scanner (System.in); public B (A a) { this .a = a; } @Override public void run () { while (true ) { System.out.println("请输入你指令(Q)表示退出:" ); char key = scanner.next().toUpperCase().charAt(0 ); if (key == 'Q' ) { a.setLoop(false ); System.out.println("b线程退出." ); break ; } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Homework02 { public static void main (String[] args) { Money money = new Money (); new Thread (money).start(); new Thread (money).start(); } } class Money implements Runnable { private int balance = 11000 ; @Override public void run () { while (true ) { synchronized (this ) { if (balance < 1000 ) { System.out.println("余额不足" ); break ; } balance -= 1000 ; System.out.print(Thread.currentThread().getName()); System.out.println(" balance=" + balance); } try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } } } }
IO流 文件
常用的文件操作
new File(String pathname)//根据路径构建一个File对象
new File(File parent,String child)//根据父目录文件+子路径构建
new File(String parent,String child)//根据父目录+子路径构建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import org.junit.jupiter.api.Test;import java.io.File;import java.io.IOException;public class FileCreate { public static void main (String[] args) { } @Test public void create01 () { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\file_\\new1.txt" ; File file = new File (filePath); try { file.createNewFile(); System.out.println("文件创建成功" ); } catch (IOException e) { e.printStackTrace(); } } @Test public void create02 () { File parentFile = new File ("D:\\Java_Project\\basicOfJava\\io_\\file_\\" ); String fileName = "new2.txt" ; File file = new File (parentFile, fileName); try { file.createNewFile(); System.out.println("文件创建成功" ); } catch (IOException e) { e.printStackTrace(); } } @Test public void create03 () { String parentPath = "D:\\Java_Project\\basicOfJava\\io_\\file_\\" ; String fileName = "news3.txt" ; File file = new File (parentPath, fileName); try { file.createNewFile(); System.out.println("创建成功~" ); } catch (IOException e) { e.printStackTrace(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import org.junit.jupiter.api.Test;import java.io.File;public class FileInformation { public static void main (String[] args) { } @Test public void info () { File file = new File ("D:\\Java_Project\\basicOfJava\\io_\\file_\\news1.txt" ); System.out.println("文件名字=" +file.getName()); System.out.println("文件绝对路径=" +file.getAbsolutePath()); System.out.println("文件父级目录=" +file.getParent()); System.out.println("文件大小(字节)=" +file.length()); System.out.println("文件是否存在=" +file.exists()); System.out.println("是不是一文件=" +file.isFile()); System.out.println("是不是一个目录" +file.isDirectory()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 public class Directory_ { public static void main (String[] args) { } @Test public void m1 () { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\file_\\news2.txt" ; File file = new File (filePath); if (file.exists()) { if (file.delete()) { System.out.println(filePath + "删除成功" ); } else { System.out.println(filePath + "删除失败" ); } } else { System.out.println("该文件不存在..." ); } } @Test public void m2 () { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\file_\\demo02" ; File file = new File (filePath); if (file.exists()) { if (file.delete()) { System.out.println(filePath + "删除成功" ); } else { System.out.println(filePath + "删除失败" ); } } else { System.out.println("该目录不存在..." ); } } @Test public void m3 () { String directoryPath = "D:\\Java_Project\\basicOfJava\\io_\\file_\\demo01\\a\\b\\c" ; File file = new File (directoryPath); if (file.exists()) { System.out.println(directoryPath + "存在.." ); } else { if (file.mkdirs()) { System.out.println(directoryPath + "创建成功.." ); } else { System.out.println(directoryPath + "创建失败..." ); } } } }
IO流分类
InputStream:字节输入流
InputStream抽象类是所有类字节输入流的超类
InputStream常用的子类
1.FilelnputStream:文件输入流
2.BufferedInputStream:缓冲字节输入流
3.ObjectInputStream:对象字节输入流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 import org.junit.Test;import java.io.FileInputStream;import java.io.IOException;public class FileInputStream_ { public static void main (String[] args) { } @Test public void readFile01 () { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\inputstream_\\hello.txt" ; int readData = 0 ; FileInputStream fileInputStream = null ; try { fileInputStream = new FileInputStream (filePath); while ((readData = fileInputStream.read()) != -1 ) { System.out.print((char ) readData); } } catch (IOException e) { e.printStackTrace(); } finally { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } @Test public void readFile02 () { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\inputstream_\\hello.txt" ; byte [] buf = new byte [8 ]; int readLen = 0 ; FileInputStream fileInputStream = null ; try { fileInputStream = new FileInputStream (filePath); while ((readLen = fileInputStream.read(buf)) != -1 ) { System.out.print(new String (buf, 0 , readLen)); } } catch (IOException e) { e.printStackTrace(); } finally { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
OutputStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import org.junit.jupiter.api.Test;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;public class FileOutputStream01 { public static void main (String[] args) { } @Test public void writeFile () throws IOException { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\outputstream_\\a.txt" ; File file = new File (filePath); if (!file.exists()) { file.createNewFile(); } OutputStream out = null ; out = new FileOutputStream (filePath); out.write("hello,world!" .getBytes()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import org.junit.jupiter.api.Test;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class FileCopy { public static void main (String[] args) { } @Test public void copyFile () { String path1 = "D:\\Java_Project\\basicOfJava\\io_\\inputstream_\\hello.txt" ; String path2 = "D:\\Java_Project\\basicOfJava\\io_\\outputstream_\\hello.txt" ; FileInputStream fileInput = null ; FileOutputStream fileOutput = null ; try { fileInput = new FileInputStream (path1); fileOutput = new FileOutputStream (path2); byte [] buf = new byte [1024 ]; int readLen = 0 ; while ((readLen = fileInput.read(buf)) != -1 ) { fileOutput.write(buf, 0 , readLen); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fileInput != null ) { fileInput.close(); } if (fileOutput != null ) { fileOutput.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
FileReader FileReader 相关方法:
new FileReader(File/String)
read:每次读取单个字符,返回该字符,如果到文件末尾返回-1
read(char[):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
相关API:
new String(char):将char[]转换成String
new String(char[,off,len):将char的指定部分转换成String
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package io_.reader_;import java.io.FileReader;import java.io.IOException;public class FileReader_ { public static void main (String[] args) { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\reader_\\story.txt" ; FileReader fileReader = null ; try { fileReader = new FileReader (filePath); System.out.println("按单个字符读取" ); int data = 0 ; while ((data = fileReader.read()) != -1 ) { System.out.print((char ) data); } System.out.println(); fileReader = new FileReader (filePath); System.out.println("按字符数组读取" ); char [] chars = new char [8 ]; int readLen = 0 ; while ((readLen = fileReader.read(chars)) != -1 ) { System.out.print(new String (chars, 0 , readLen)); } } catch (IOException e) { e.printStackTrace(); } finally { if (fileReader != null ) { try { fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
FileWriter FileWriter相关方法
new FileWriter(File/String):覆盖模式,相当于流的指针在首端
new FileWriter(File/String,true):追加模式,相当于流的指针在尾端
write(int):写入单个字符
write(char[]):写入指定数组
write(char[],off,len):写入指定数组的指定部分
write (string):写入整个字符串
write(string,off,len):写入字符串的指定部分
相关API: String类:toCharArray:将String转换成char
注意 :FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.io.FileWriter;import java.io.IOException;public class FileWriter_ { public static void main (String[] args) { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\writer_\\note.txt" ; FileWriter fileWriter = null ; char [] chars = {'a' , 'b' , 'c' }; try { fileWriter = new FileWriter (filePath); fileWriter.write('H' ); fileWriter.write(chars); fileWriter.write("学习学习" .toCharArray(), 0 , 3 ); fileWriter.write(" 你好北京~" ); fileWriter.write("风雨之后,定见彩虹" ); fileWriter.write("上海天津" , 0 , 2 ); } catch (IOException e) { e.printStackTrace(); } finally { try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } }
节点流和处理流 节点流 可以从一个特定的数据源读写数据,如FIleReader、FileWriter
处理流 (也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter
节点流和处理流的区别和联系
节点流是底层流/低级流,直接跟数据源相接。
处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连
BufferedReader 1 2 3 4 5 6 7 8 9 10 11 12 import java.io.*;public class BufferedReader_ { public static void main (String[] args) throws IOException { BufferedReader reader = new BufferedReader (new FileReader ("D:\\Java_Project\\basicOfJava\\io_\\reader_\\story.txt" )); String line; while ((line = reader.readLine()) != null ) { System.out.println(line); } reader.close(); } }
BufferedWriter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;public class BufferedWriter_ { public static void main (String[] args) throws IOException { BufferedWriter bw = new BufferedWriter (new FileWriter ("D:\\Java_Project\\basicOfJava\\io_\\writer_\\note.txt" ,true )); bw.newLine(); bw.write("Hello World" ); bw.newLine(); bw.write("goodbye world" ); bw.close(); } }
BufferedInputStream是字节流在创建BufferedInputStream时,会创建一个内部缓冲区数组.
BufferedOutputStream BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.io.*;public class BufferedCopy02 { public static void main (String[] args) throws IOException { String srcFilePath = "D:\\Java_Project\\basicOfJava\\io_\\inputstream_\\高山流水.mp3" ; String dstFilePath = "D:\\Java_Project\\basicOfJava\\io_\\outputstream_\\高山流水.mp3" ; BufferedInputStream bis = new BufferedInputStream (new FileInputStream (srcFilePath)); BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream (dstFilePath)); byte [] bytes = new byte [1024 ]; int readLen = 0 ; while ((readLen = bis.read(bytes)) != -1 ) { bos.write(bytes, 0 , readLen); } bis.close(); bos.close(); } }
ObjectOutputStream 序列化和反序列化
1.序列化就是在保存数据时,保存数据的值和数据类型
2.反序列化就是在恢复数据时,恢复数据的值和数据类型
3.需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一: Serializable //这是一个标记接口,没有方法 Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口
ObjectOutputStream 提供 序列化功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import java.io.FileOutputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class ObjectOutStream_ { public static void main (String[] args) throws Exception { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\outputstream_\\data.dat" ; ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream (filePath)); oos.writeInt(100 ); oos.writeBoolean(true ); oos.writeChar('a' ); oos.writeDouble(9.5 ); oos.writeUTF("学习学习" ); oos.writeObject(new Dog (10 )); oos.close(); System.out.println("数据保存完毕(序列化形式)" ); } } class Dog implements Serializable { int age; public Dog (int age) { this .age = age; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;public class ObjectInputStream_ { public static void main (String[] args) throws IOException, ClassNotFoundException { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\outputstream_\\data.dat" ; ObjectInputStream ois = new ObjectInputStream (new FileInputStream (filePath)); System.out.println(ois.readInt()); System.out.println(ois.readBoolean()); System.out.println(ois.readChar()); System.out.println(ois.readDouble()); System.out.println(ois.readUTF()); System.out.println(ois.readObject()); ois.close(); System.out.println("以反序列化的方式读取(恢复)ok~" ); } }
1)读写顺序要一致
2)要求序列化或反序列化对象,需要实现 Serializable
3)序列化的类中建议添加SerialVersionUID.为了提高版本的兼容性
4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
5)序列化对象时,要求里面属性的类型也需要实现序列化接口
6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化
标准输入输出流
转换流 1.InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成(换)Reader(字符流)
2.OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(宁符流)
3.当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
4.可以在使用时指定编码格式(比如utf-8, gbk , gb2312, IS08859-1等)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;public class InputStreamReader_ { public static void main (String[] args) throws IOException { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\transformation_\\a.txt" ; BufferedReader br = new BufferedReader (new InputStreamReader ( new FileInputStream (filePath), "gbk" )); String s = br.readLine(); System.out.println("读取内容=" + s); br.close(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;public class OutputStreamWriter_ { public static void main (String[] args) throws IOException { String filePath = "D:\\Java_Project\\basicOfJava\\io_\\transformation_\\b.txt" ; OutputStreamWriter osw = new OutputStreamWriter (new FileOutputStream (filePath), "gbk" ); osw.write("god,天" ); osw.close(); } }
打印流 PrintStream PrintStream (字节打印流/输出流)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.io.IOException;import java.io.PrintStream;public class PrintStream_ { public static void main (String[] args) throws IOException { PrintStream out = System.out; out.print("Hello, world!\n" ); out.write("Hello, 世界!" .getBytes()); System.setOut(new PrintStream ("D:\\Java_Project\\basicOfJava\\io_\\printstream_\\p1.txt" )); System.out.println("goodbye, world!" ); out.close(); } }
PrintWriter 1 2 3 4 5 6 7 8 9 10 public class PrintWriter_ { public static void main (String[] args) throws IOException { PrintWriter printWriter = new PrintWriter (new FileWriter ("D:\\Java_Project\\basicOfJava\\io_\\printstream_\\p2.txt" )); printWriter.print("hi, 北京你好~~~~" ); printWriter.close(); } }
Properties类 1)专门用于读写配置文件的集合类
配置文件的格式:
键=值
键=值
2)注意:键值对不需要有空格,值不需要用引号一起来。默认类型是String
3)Properties的常见方法
load:加载配置文件的键值对到Properties对象
list:将数据显示到指定设备
getProperty(key):根据键获取值
setProperty(key,value):设置键值对到Properties对象
store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含
有中文,会存储为unicode码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Properties02 { public static void main (String[] args) throws IOException { Properties properties = new Properties (); properties.load(new FileReader ("src\\mysql.properties" )); properties.list(System.out); String user = properties.getProperty("user" ); String pwd = properties.getProperty("pwd" ); System.out.println("用户名=" + user); System.out.println("密码是=" + pwd); Properties properties2 = new Properties (); properties2.setProperty("charset" , "utf8" ); properties2.setProperty("user" , "汤姆" ); properties2.setProperty("pwd" ,"888888" ); properties2.store(new FileOutputStream ("src\\mysql2.properties" ), "hello world" ); System.out.println("保存配置文件成功~" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package reflection_;public class Cat { private String name = "招财猫" ; public int age = 10 ; public Cat () {} public Cat (String name) { this .name = name; } public void hi () { } public void cry () { System.out.println(name + " 喵喵叫.." ); } }