一、类变量和类方法
1. 类变量
类变量(静态变量/静态属性):是该类所有对象共享的变量,该类所有的对象都可以对齐进行修改或引用。
语法:static : 表示静态
1 2 3
| 访问修饰符 static 数据类型 变量名;(推荐该写法)
static 访问修饰符 数据类型 变量名;
|
引用语法:
1 2 3
| 类名.类变量名;(推荐使用)
对象名.类变量名;
|
- 类变量是随着类的加载而创建的,即使没有创建对象,也可以访问;
- 类变量的访问,也要遵守访问修饰符的访问权限;
- 没有加 static 则表示为实例变量,不共享,加上则表示为 类变量,是共享的;
- 类变量的生命周期时随着类的加载而加载,随着类的消亡而消亡;
2.类方法
类方法,也叫静态方法;
语法:
1
| 访问修饰符 static 返回数据类型 方法名(){};(推荐写法)
|
调用:
- 静态方法既可以通过类调用,也可以通过类调用;
- 非静态方法不能通过类调用,只能通过对象调用;
- 类方法中不允许使用和对象有关的关键字
- 如: this,super
- 静态方法中,只能访问静态变量或静态方法
- 普通成员方法 都可以访问;
静态方法,只能访问静态的成员; > 普通方法,静态与非静态的成员都可以访问;
使用场景:
二、代码块
代码块(初始化块):属于类中的成员,类似于方法,将逻辑语句封装在方法体中,通过{}包围起来;
与方法不同,没有方法名,没有返回,没有参数,只有方法体,不能通过对象或类显式调用,在加载类或创建对象时隐式调用
语法:
- 修饰符 可选,要写只能写 static
- 没有修饰符的叫普通代码块,有修饰符的叫静态代码块
- “;” 可以省略
- 代码块的调用顺序优先于构造器
类什么时候加载:
- 创建实例对象时
- 创建子类对象实例时,父类也会加载(父类先加载,子类后加载);
- 使用类的静态成员时
细节:
- 静态代码块只会执行一次,普通代码块 每创建一个对象,就会执行一次
- 如果只使用静态成员时,普通成员不会执行
- 创建对象时,类 调用顺序:
- 调用静态代码块和静态属性初始化(优先级一样,多个时按定义顺序调用)
- 调用普通代码块和普通属性的初始化(同上)
- 调用构造器方法
- 构造器的前面隐含了 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
| public class StaticDemo01 { public static void main(String[] args) { StaticDemo01.demo1(); System.out.println("======================"); new StaticDemo01().demo2(); }
private static String name1 = getName1(); private String name2 = getName2();
public static String getName1() { System.out.println("静态属性 被执行~~~"); return name1; }
public String getName2() { System.out.println("普通属性 被执行~~~"); return name2; }
{ System.out.println("普通代码块 被执行~~~"); } static { System.out.println("静态代码块 被执行~~~"); } public static void demo1(){ System.out.println("静态方法 被执行~~~"); } public void demo2(){ System.out.println("普通方法 被执行~~~"); }
public StaticDemo01() { System.out.println("构造函数 被执行~~~"); } }
|
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 StaticDemo02 { public static void main(String[] args) { Test a = new Test(); } }
class Sample{ Sample(String s){ System.out.println(s); } Sample(){ System.out.println("Sample 默认构造器函数被调用"); } } class Test{ Sample sam1 = new Sample("sam1 成员初始化"); static Sample sam = new Sample("静态成员 sam 初始化"); static { System.out.println("static 快执行"); if (sam == null){ System.out.println("sam is null"); } } Test(){ System.out.println("Test 默认构造器函数被调用"); } }
|
三、单例设计模式
单例模式: 采取一定的方法,使某个类只存在一个对象实例,并且该类只提供一个获取对象实例的方法。
单例模式:
①。饿汉式: 类在加载时直接创建一个对象,不管后续有没有使用;
②。懒汉式: 只有当使用时,类才会加载一个对象;
饿汉式 和 懒汉式 设计模式的实现:
- 构造器私有化(防止直接 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
| public class SingleTon01 { public static void main(String[] args) { GirlFriend friend = GirlFriend.getInstance(); System.out.println(friend); } }
class GirlFriend{ private String name; private GirlFriend(String name) { this.name = name; } private static GirlFriend gf = new GirlFriend("小汪"); public static GirlFriend getInstance(){ return gf; }
@Override public String toString() { return "GirlFriend{" + "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
| public class SingleTon02 { public static void main(String[] args) { Cat c = Cat.getInstance(); System.out.println(c); } }
class Cat{ private String name; private static Cat cat;
private Cat(String name) { 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 可以用于修饰类、属性、方法、局部变量等
使用场景:
- 当不希望类被继承时,可以使用 final 修饰
- 当不希望父类的某个方法被子类覆盖、重写时,可以使用 final 关键字修饰
- 当不希望某个属性的值被修改时,可以使用 final 修饰
- 当不希望某个是不变量被修改时,可以使用 final 修饰
注意事项:
- final 修饰的属性又叫常量,一般用 全大写字母 和 下划线 来命名
- NUM_TEST
- final 修饰的属性在定义时,必须赋初始值,并且以后不能再修改
- 定义时:如:public final double TAX_RATE = 0.08;
- 在构造器中赋值;
- 在代码块中赋值;
- 如果 final 修饰的是静态属性,则初始化的位置只能
- 在定义时
- 在静态代码块中
- 不能在构造器中赋值
- final 类不能继承,但是可以实例化对象
- 如果类不是 final 类,但是含有 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
| public class Final01 { public static void main(String[] args) { System.out.println(new AA("小王")); CC cc = new CC(); cc.prints(); } }
class AA{ public final double TAX_RATE = 0.08; private final String name; private final int age;
{ age = 18; } public AA(String name) { this.name = name; }
@Override public String toString() { return "AA{" + "TAX_RATE=" + TAX_RATE + ", name='" + name + '\'' + ", age=" + age + '}'; } }
class BB{ private static final String name; private static final int age = 18; static { name = "小明"; } public final void prints(){ System.out.printf("name=%s,age=%d",name,age); } }
class CC extends BB{ }
|
五、抽象类(abstract)
抽象类: 当类中的某些方法不确定时,就可以使用 abstract 关键字将方法修饰为抽象方法,用 abstract 修饰类成为抽象类,一般都会由子类继承,由子类来实现抽象方法。
语法:
1 2 3 4
| abstract class Demo{ public abstract String demo(); }
|
注意事项:
- 抽象类和抽象方法必须使用 abstract 修饰;
- 抽象方法没有方法体;
- 抽象类一般都会被继承,由子类重写抽象方法;
- 抽象类不能实例化;
- 抽象类不一定有抽象方法,但是有抽象方法,则必须是抽象类;
- abstract 只能修饰 类 或 方法;
- 如果继承了抽象类,则必须实现抽象方法,或者自己也申明为抽象类
- 抽象方法不能用 final、static、private 来修饰,与抽象方法规则相违背;
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
| abstract public class Employee { private String name; private int age; private double salary;
public Employee(String name, int age, double salary) { this.name = name; this.age = age; this.salary = salary; }
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 double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
abstract public void work(); }
class CommonEmployee extends Employee{ public CommonEmployee(String name, int age, double salary) { super(name, age, salary); }
@Override public void work() { System.out.printf("普通员工 %s 工作中~~~\n",getName()); } }
class Manager extends Employee{ private double bonus;
public Manager(String name, int age, double salary, double bonus) { super(name, age, salary); this.bonus = bonus; }
public double getBonus() { return bonus; }
public void setBonus(double bonus) { this.bonus = bonus; }
@Override public void work() { System.out.printf("经理 %s 工作中……\n",getName()); } }
class Test{ public static void main(String[] args) { CommonEmployee ce = new CommonEmployee("小李", 25, 3000); ce.work(); Manager mg = new Manager("老王", 40, 5000, 1000); mg.work(); } }
|
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 AbstractTime { public static void main(String[] args) { AA aa = new AA(); aa.calculateTime(); } }
abstract class Template{ public abstract void job(); public void calculateTime(){ long startTime = System.currentTimeMillis(); job(); long endTime = System.currentTimeMillis(); System.out.printf("执行时间为:%d",(endTime-startTime)); } }
class AA extends Template{ @Override public void job() { for (int i = 1; i <= 8000000 ; i++) { i++; } } }
|
六、接口
接口: 就是给出一些没有实现的方法封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
使用 interface 来定义接口
使用 implement 来实现接口
语法:
1 2 3 4 5 6 7 8
| interface 接口名{ 属性或方法; }
class 类名 implement 接口名{ 自己的属性或方法; 必须实现抽象方法; }
|
注意事项:
- 接口不能被实例化;
- 接口中所有的方法都是 public 方法,接口中的抽象方法 可以不用 abstract 修饰
- 一个普通类实现接口,就必须将该接口的所有方法都实现
- 抽象类实现接口,可以不用实现接口的方法
- 一个类同时可以实现多个接口
- 接口中的属性,只能是 final 的,而且是 public static final 修饰符
- 如: int a =1; 实际上是 public static final int a = 1;(必须初始化)
- 接口中属性的访问形式: 接口名.属性名
- 一个接口不能继承其他的类,但是可以继承多个接口
- 如: interface A extends B,C{}
- 接口的修饰符只能是 public 和 默认,这点和 类的修饰符一样
当子类继承类父类,就自动拥有父类的功能,如果子类需要扩展功能,则可以通过实现接口的方式扩展
实现接口 是对 java 单继承的一个补充
继承 与 接口实现的区别:
- 继承时,会自动拥有父类的所有功能;
- 接口是对 单继承的一种补充,用于扩展子类功能
- 继承主要解决代码的复用性和可维护性
- 接口主要用于设计各种规范,让其他类去实现这些方法
- 接口相较于继承更加灵活
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 ExtendsVsInterface { public static void main(String[] args) { LittleMonkey wk = new LittleMonkey("悟空"); wk.work(); wk.flying(); wk.swimming(); } }
class Monkey{ private String name;
public Monkey(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public void work(){ System.out.println(String.format("%s 会爬树",name)); } }
class LittleMonkey extends Monkey implements FishAble,BirdAble{ public LittleMonkey(String name) { super(name); }
@Override public void swimming() { System.out.printf("%s 通过学习,可以像鱼一样游泳~\n",getName()); }
@Override public void flying() { System.out.printf("%s 通过学习,可以像鸟一样飞翔~\n",getName()); } }
interface FishAble{ void swimming(); }
interface BirdAble{ void flying(); }
|
接口的多态特性:
- 多态参数(一个接口有多个方法实现时,通过参数判断实现对象)
- 多态数组
- 多态传递(一个接口继承了另一个接口)
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 InterfacePoly { 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++) { if (usbs[i] instanceof Phone_){ ((Phone_) usbs[i]).call(); } usbs[i].work(); } } }
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
| class Outer{ class Inner{ } }
|
内部类的分类:
- 根据定义在外部类的位置:
- 局部内部类(有类名)
- 匿名内部类(没有类名)
- 根据定义在外部类的成员位置:
- 成员内部类(没有 static 修饰)
- 静态内部类(有 static 修饰)
1. 局部内部类
说明:
- 通常定义在方法中;
- 可以直接访问外部类的所有成员,包括私有的属性或方法;
- 不能添加访问修饰符,但是可以使用 final 修饰符
- 作用域:只在定义他的方法或代码块中使用``
- 局部内部类访问外部类时,可以直接访问
- 外部类访问局部内部类时,需要先创建对象,在进行访问
- 外部其他类不能访问局部内部类
- 如果外部类和内部类的成员重名,则默认采取就近原则,
- 如果要访问外部类成员,可以使用 外部类.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 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class LocalClass { public static void main(String[] args) { AA aa = new AA("老王"); aa.method1();
} }
class AA{ private String name;
public AA(String name) { this.name = name; }
public void method1(){ final class BB{ private String name;
public BB(String name) { this.name = name; } public void method1(){ System.out.printf("局部内部类,内部类 name= %s,外部类 name= %s\n",name,AA.this.name); }
public String getName() { return name; }
public void setName(String name) { this.name = name; } } BB bb = new BB("张三"); bb.method1(); System.out.println("访问类外部类方法"); }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
2.匿名内部类
语法:
注意事项:
- 调用匿名内部类的方法:
new A(){}.cry();
A a = new A(){}; a.cry();
- 可以直接访问外部类的所有成员,包括私有属性
- 不能添加访问修饰符,因为它就是一个局部变量
- 作用域:仅定义在他的方法或代码块中
- 外部其他类,不能访问匿名内部类
- 外部类和内部类的成员重名时,默认遵守就近原则;
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 LocalClass2 { public static void main(String[] args) { Cellphone cellphone = new Cellphone(); cellphone.alarmclock(new Bell() { @Override public void ring() { System.out.println("懒猪起床了"); } }); cellphone.alarmclock(new Bell() { @Override public void ring() { System.out.println("小伙伴们上课了"); } }); } }
interface Bell{ void ring(); }
class Cellphone{ public void alarmclock(Bell bell){ bell.ring(); } }
|
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
| public class AnonymousInnerClass { public static void main(String[] args) { Other01 other01 = new Other01(); other01.method1(); } }
class Other01{ public void method1(){ IA tiger = new IA() { @Override public void cry() { System.out.println("老虎叫~~~"); } }; tiger.cry();
Father father = new Father("张三"){ @Override public void test() { System.out.println("匿名内部类重写类 test 方法"); } }; father.test();
Animal animal = new Animal(){ @Override void eat() { System.out.println("实现抽象类的抽象方法"); } }; animal.eat(); } }
interface IA{ void cry(); }
class Father{ String name; public Father(String name){ this.name = name; }; public void test(){ System.out.println(name); }; }
abstract class Animal{ abstract void eat(); }
|
3.成员内部类
成员内部类定义在外部类的成员位置,并且没有 static 修饰
- 可以直接访问外部类的所有成员,包括私有成员
- 可以添加任意访问修饰符(public、protected、默认、private),他的定位时成员;
- 作用域:和外部类的成员方法一样
- 成员内部类 可以直接访问 外部类
- 外部类 访问 成员内部类时,需要先创建内部类对象,再访问
- 外部其他类 可以访问 内部成员类
- 如果外部类和内部类的成员重名,则默认遵守就近原则
- 如果要访问外部类成员,则 通过(外部类名.this.成员名)访问
1 2 3 4 5 6 7 8 9 10 11
|
Outer1 outer1 = new Outer1(); Innter1 innter1 = outer1.new Innter1();
Innter2 innter2 = new Outer2().new Innter2();
Innter3 innter3d = new Outer3().getInnter3();
|
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 LocalClass3 { public static void main(String[] args) { Outer1 outer1 = new Outer1(); outer1.t1();
Outer1.Inner1 inner1 = outer1.new Inner1(); inner1.say(); Outer1.Inner1 inner1 = outer1.getInner1(); inner1.say(); } }
class Outer1 { private int n1 = 10; private String name = "张三"; public class Inner1{ public void say(){ System.out.printf("n1= %d,name= %s",n1,name); } }
public void t1(){ Inner1 inner1 = new Inner1(); inner1.say(); }
public Inner1 getInner1(){ return new Inner1(); } }
|
4.静态内部类
静态内部类定义在 外部类的成员位置, 并且有 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 50 51
| public class LocalClass3 { public static void main(String[] args) { Outer1 outer1 = new Outer1(); outer1.m1();
Outer1.Inner1 inner1 = new Outer1.Inner1(); inner1.say();
Outer1.Inner1 inner11 = outer1.getInner1(); inner11.say();
Outer1.Inner1 inner2 = Outer1.getInner2(); inner2.say(); } }
class Outer1 { private int n1 = 10; private static String name = "张三";
public static void cry(){ System.out.println("静态方法"); };
public static class Inner1{ public void say(){ System.out.println(name); cry(); } }
public void m1(){ Inner1 inner1 = new Inner1(); inner1.say(); }
public Inner1 getInner1(){ return new Inner1(); }
public static Inner1 getInner2(){ return new Inner1(); } }
|