教程:b站韩顺平
类变量名也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量
定义:
访问修饰符 static 数据类型 变量名;
访问:
类名.类变量名(推荐)
对象名.类变量名 //静态变量的访问修饰符的访问权限和范围 和 普通属性 是一样的
注意事项和细节讨论:
类方法,即静态方法
定义:
访问修饰符 static 数据返回类型 方法名(){}
调用:
类名.类方法名()
对象名.类方法名() //前提是满足访问修饰符的访问权限和范围
类方法经典使用场景:
当方法中不涉及到任何和对象相关的成员,则可以将该方法设计成静态方法,提高开发效率
例如工具类中的方法:Math类、Array类等
注意事项:
小结:
main()方法的形式
public static void main(String[] args){}
代码化块又成为初始化块,属于类中的成员【即 是类的一部分】,类似于方法,将逻辑语句封装在方法体中,通过{}包围
和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不能通过对象或类显示调用,而是加载类时,或创建对象是隐式调用
基本语法
[修饰符]{
代码
};
tips: 修饰符 可选,要写的话,也只能写static
代码块分为两类:
- 使用static:静态代码块
- 没有static修饰:普通代码块
创建一个对象时:
构造方法(构造器)的最前面其实隐含了super()和调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于 构造器和普通代码执行的
创建一个子类时:
静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员
public final double TAX_RATE=0.08;
final double TAX_RATE-0.08;
当父类的某些方法,需要声明,但是又不确定如何是实现时,可以将其声明为抽象方法,那么这个类就是抽象类
抽象类:
a. 不能被实例化
b. 可以有任意成员,比如非抽象方法、构造器、静态属性等
c. 多用于框架和设计模式
d. 抽象类的价值更多作用在于设计,是设计者设计好后,让子类继承并实现抽象类
e. 如果一个类继承了抽象类,则它需要实现抽象类的所有抽象方法,除非他自己也声明为一个abstract类
f. 抽象类不一定要包含abstract方法
g. 一旦类包含abstract方法,则该类必须声明为abstract
h. abstract只能修饰类和方法,不能修饰属性和其他
访问修饰符 abstract 类名{
}
抽象方法:没有方法体
访问修饰符 abstract 返回类型 方法名(参数列表);
抽象方法不能使用 private、final、static 修饰, 因为这些关键字和重写相违背
应用:模板设计模式
//1. 声明接口
interface 接口名{
//属性
//方法(1.抽象方法2.默认实现方法3.静态方法)
}
//2. 类使用接口,则必须实现接口中的方法
class 类名 implements 接口{
//自己属性
//自己方法
//必须实现的接口的抽象方法
}
default public void ok(){
}
public interface UsbInterface {
public void start();
public void stop();
}
Camera.java
public class Camera implements UsbInterface{
public void start(){
System.out.println("相机开始工作");
}
public void stop(){
System.out.println("相机停止工作");
}
}
Phone.java
public class Phone implements UsbInterface{
public void start(){
System.out.println("手机开始工作");
}
public void stop(){
System.out.println("手机停止工作");
}
}
Computer.java
public class Computer {
public void work(UsbInterface usbInterface){
usbInterface.start();
usbInterface.stop();
}
}
InterfaceExercise.java
public class InterfaceExercise {
public static void main(String[] args){
Camera camera = new Camera();
Computer computer = new Computer();
computer.work(camera); //把相机接入电脑
}
}
interface A {
int x=0;
}
class B{
int x=1;
}
class C extends B implements A{
public void pX(){
System.out.println(super.x);
System.out.println(A.x);
}
public static void main(String[] args){
//因为pX不是静态类,所以调用时需要创建对象
new C().pX();
}
}
接口的注意事项和细节
a. 接口不能被实例化
b. 接口中所有的方法时public方法,接口中抽象方法,可以不用abstract修饰
void aaa();
//实际上是 abstract void aaa();
c. 一个普通类实现接口,就必须将该接口的所有方法都实现
d. 抽象类实现接口,可以不用实现接口的方法
e. 一个类同时可以实现多个接口
f. 接口中的属性,只能是final,而且是
public static final 修饰符
// public static final int a=1;(必须初始化)
g. 一个接口不能继承其他的类,但是可以继承多个别的接口
interface A extends B,C{}
h. 接口的修饰符 只能是public和默认,这点和类的修饰符是一样的
实现接口 vs 继承类
a. 接口和继承解决的问题不同
ⅰ. 继承:解决代码复用性和可维护性
ⅱ. 接口:设计好各种规范(方法),让其他类去实现这些方法
b. 接口比继承更加灵活
ⅰ. 继承:is-a
ⅱ. 接口:like-a
c. 接口在一定程度上实现代码解耦【接口规范性+动态绑定】
接口的多态特性
a. 多态参数:在USB案例中,接口既可以接收手机,又可以接收相机(接口引用可以指向实现了接口的类的对象)
b. 多态数组
Usb usbs[]=new usb[2];
usbs[0]=new Phone();
usbs[1]=new Camera();
for(int i=0;i<usbs.length;i++){
usbs[i].start();
usbs[i].stop();
}
if(usbs[i] instanceof Phone){
((Phone)usbs[i]).call();
}
c. 多态传递
interfce AInterface{
void f1();
}
class B implements AInterface{
@Override
public void f1(){
System.out.println("f1!");
}
}
class C extends B{}
//....
C c = new C();
AInterface af = c;
一个类的内部又完整地嵌套了另一个类结构,被嵌套的类为内部类,嵌套其他类的类称为外部类
class Outer{ //外部类
class Inner{ //内部类
}
}
class Other{ //外部其他类
}
public class InnerClass {
public static void main(){
Outer outer = new Outer();
outer.m1();
}
}
class Outer{
private int n1=100;
private void m2(){}//私有方法
public void m1(){
final class Inner{
public void f1(){
System.out.println("n1="+n1);
m2();
}
}
Inner inner=new Inner();
inner.f1();
}
}
特点:
a. 本质是类
b. 内部类
c. 该类没有名字
d. 同时还是一个对象
说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
基本语法:
new 类或接口(参数列表){
类体
};
案例1-基于接口的匿名内部类:
public class AnonymousClass {
public static void main(String[] args){
IA tiger = new Tiger();
tiger.cry();
}
}
interface IA{
public void cry();
}
class Tiger implements IA{
public void cry(){
System.out.println("Tiger cry");
}
}
将上面代码转变为匿名内部类的形式:
public class AnonymousClass {
public static void main(String[] args){
IA tiger = new IA(){
public void cry(){
System.out.println("老虎叫唤");
}
};
tiger.cry();
System.out.println(tiger.getClass());
}
}
interface IA{
public void cry();
}
● tiger编译类型:tiger
● tiger运行类型:匿名内部类 AnonymousClass$1(系统分配)
class AnonymousClass$1 implements IA{
@Override
public void cry(){
System.out.println("老虎叫唤");
}
}
● jdk在底层创建匿名内部类 AnonymousClass$1,立马就创建了AnonymousClass$1实例,并把地址返回给tiger
● 匿名内部类使用一次就不能再使用了,但是可以被多次调用
案例2-基于类的匿名内部类
public class AnonymousClass {
public static void main(String[] args){
Father father1 = new Father("father1");
father1.test();
Father father2 = new Father("father2"){
@Override
public void test(){
System.out.println("匿名内部类重写了test方法");
}
};
father2.test();
System.out.println("father2的运行类型:"+father2.getClass());
}
}
class Father{
private String name;
public Father(String name){
this.name=name;
}
public void test(){
System.out.println("Father\t"+this.name+"\ttest()");
}
}
● 系统创建AnonymousClass$1,立马就创建了AnonymousClass$1实例,并把地址返回给father2
class AnonymousClass$1 extends Father{
@Override
public void test(){
System.out.println("匿名内部类重写了test方法");
}
}
案例-基于抽象类的匿名内部类
abstract class Animal{
abstract void eat();
}
Animal animal = new Animal(){
@Overrider
void eat(){ //因为抽象类Animal,所以必须实现eat()
System.out.println("小狗吃骨头");
}
}
使用细节
● 可以直接访问外部类的所有成员,包含私有的
● 不能添加访问修饰符,因为它的地位就是一个局部变量
● 作用域:仅仅在定义它的方法或代码块中
● 匿名内部类 访问——>外部类成员【直接访问】
● 外部其他类 不能访问——>匿名内部类【应为匿名内部类地位=局部变量】
● 外部类 和 内部类 成员重名是,内部类访问遵循就近原则,访问外部类成员: 外部类名.this.成员
● 练习
public class InnerClassExercise {
public static void main(String[] args){
Bell getup = new Bell() {
@Override
public void Ring() {
System.out.println("getup!!");
}
};
Bell gotoClass = new Bell() {
@Override
public void Ring() {
System.out.println("goutoClass!!");
}
};
CellPhone cellPhone = new CellPhone();
cellPhone.alarmclock(getup);
cellPhone.alarmclock(gotoClass);
}
}
interface Bell{
void Ring();
}
class CellPhone{
public void alarmclock(Bell bell){
System.out.println(bell.getClass());
bell.Ring();//方法是动态绑定机制
}
}
成员内部类是定义在外部类的成员位置,并没有static修饰
可以直接访问外部类的所有成员,包括私有的
可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员
作用域:和外部类的其他成员一样,为整个类体,在外部类的成员方法中创建成员内部类对象,再调用方法
成员内部类 访问——>外部成员【访问方式:直接访问】
外部类 访问——>内部成员【创建对象,再访问】
外部其他类 访问——成员内部类
a. 法一: 直接创建
Outer.Inner inner = outer.new Inner();
b. 法二:在外部类中,编写一个方法返回成员内部类对象
Outer.Inner innerInstance = outer.getInnerInstance();
innerInstance.say();
如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
class A{
private int n1=10;
private static String name = "name";
class B{
private int n1=20;
public void sat(){
System.out.println("A n1"+A.this.n1+"B n1"+n1);
}
}
}
说明:静态内部类是定义在外部类的成员位置,有static修饰
可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
可以添加任意访问修饰符public、protected、默认、private,因为其地位就是一个成员
作用域:同其他的成员,为整个类体
静态内部类 访问——外部类(如静态属性)【访问方式:直接访问所有静态成员】
外部类 访问——>静态内部类【访问方式:创建对象,再访问】
class A{
private int n1 =10;
private static String name = "tom";
private static void cry(){
System.out.println("cry");
}
static class B{
public void say(){
System.out.println(name);
cry();
}
}
public void test(){
B b = new b();
b.say();
}
}
外部其他类 访问——静态内部类
a. 因为静态内部类可以通过类名直接访问(前提:满足访问权限)
B b = new A.B();//这里就不会创建一个A对象实例
b.say();
b. 通过一个方法来获取一个静态内部类的对象实例
public class StaticClass{
public static void main(String[] args){
A a = new A();
A.B b = a.getB();
b.cry();
}
}
class A{
static class B{
public void say(){
System.out.println(name);
cry();
}
}
public B getB(){
return new B();
}
}
若修改为静态方法,会更方便,就不会创建内部类对象了
public class StaticClass{
public static void main(String[] args){
A.B b = A.getB();
b.cry();
}
}
class A{
static class B{
public void say(){
System.out.println(name);
cry();
}
}
public static B getB(){
return new B();
}
}
如果外部类和静态类内部类的成员重名是,静态内部类访问时,遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
//法一,注意没有生成A类对象实例
B b = new A.B();
b.say();
//法二:如果访问内部类的静态方法,就可以不用new
A.B.hello();