黑马Java基础笔记-10
权限修饰符
修饰符 | 同一个类中 | 同一个包中其他类 | 不同包的子类 | 不同包无关类 |
---|---|---|---|---|
private | √ | |||
空着不写 (default) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
代码块
局部代码块(了解)
public class Test {public static void main(String[] args) {{int a = 10;System.out.println(a);}//运行到此处时a就从内存中消失了}
}
构造代码块
public class Student {private String name;private int age;
??{System.out.println("开始创建对象了");}
??public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}
}
- 写在成员位置的代码块
- 作用:可以把多个构造方法中重复的代码抽取出来
- 执行时机:我们在创建本类对象的时候会先执行构造代码块再执行构造方法
静态代码块
public class Student {private String name;private int age;??static {System.out.println("静态");}
??public Student() {System.out.println("空参构造");}public Student(String name, int age) {System.out.println("有参构造");this.name = name;this.age = age;}
}
-
格式:static0
-
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
-
使用场景:在类加载的时候,做一些数据初始化的时候使用
抽象类和抽象方法
-
抽象类不能实例化
-
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
-
可以有构造方法
作用在于为继承体系中的所有子类统一初始化父类部分的状态与资源
-
抽象类的子类
- 要么重写抽象类中的所有抽象方法
- 要么是抽象类
接口
接口的定义和使用
-
接口用关键字
interface
来定义public interface 接口名 {}
-
接口不能实例化
-
接口和类之间是实现关系,通过
implements
关键字表示public class 类名 implements 接口名 {}
-
接口的子类(实现类)
- 要么重写接口中的所有抽象方法
- 要么是抽象类
注意
- 实现类还可以在继承一个类的同时实现一个或多个接口
- 当多个接口都声明了相同签名的抽象方法,实现类只需在类中实现一次即可
public class 类名 extends 父类 implement 接口名1, 接口名2 {}
接口中成员的特点
-
成员变量
- 只能是常量
- 默认修饰符:
public static final
(java默认都会自己加上的)
-
构造方法
- 没有(java也不会加上默认的无参构造)
-
成员方法
- 只能是抽象方法
- 默认修饰符:
public abstract
(java默认都会自己加上的)
-
JDK7以前:接口中只能定义抽象方法。
-
JDK8的新特性:接口中可以定义有方法体的方法。(默认、静态)
默认(default)
- 允许在接口中定义默认方法,需要使用关键字
default
修饰
作用:解决接口升级的问题(可以先不重写,给接口的实现类重写提供时间)
接口中默认方法的定义格式
-
格式:
public default 返回值类型 方法名(参数列表) { }
-
示例:
public default void show() { }
接口中默认方法的注意事项
- 默认方法不是抽象方法,所以不强制被重写。重写时实现类不要加default
public
可以省略,default
关键字不能省略- 如果实现了多个接口,且这些接口中存在相同签名的默认方法,子类必须对该方法进行重写
静态(static)
- 允许在接口中定义静态方法,需要使用
static
修饰
接口中静态方法的定义格式
- 格式:
public static 返回值类型 方法名(参数列表) { }
- 示例:
public static void show() { }
接口中静态方法的注意事项
- 静态方法只能通过接口名调用,不能通过实现类名或对象名调用
public
可以省略,static
关键字不能省略
- 允许在接口中定义默认方法,需要使用关键字
-
JDK9的新特性:接口中可以定义私有方法。
接口中私有方法的定义格式:
- 格式1:
private 返回值类型 方法名(参数列表) { }
private void show() { }
- 格式2:
private static 返回值类型 方法名(参数列表) { }
private static void method() { }
- 格式1:
接口和类之间的关系
-
类和类的关系
继承关系,只能单继承,不能多继承,但是可以多层继承 -
类和接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口 -
接口和接口的关系
继承关系,可以单继承,也可以多继承
适配器设计模式
当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以适配器设计模式
- 书写步骤:
- 编写中间类XXXAdapter实现对应的接口
- 对接口中的抽象方法进行空实现
- 让真正的实现类继承中间类,并重写需要用的方法
- 为了避免其他类创建适配器类的对象,中间的适配器类用
abstract
进行修饰
// 1. 原始接口:方法非常多
public interface Inter {void method1();void method2();void method3();void method4();void method5();void method6();void method7();
}
// 2. 适配器类:为所有方法提供“空实现”
public abstract class InterAdapter implements Inter {@Override public void method1() {}@Override public void method2() {}@Override public void method3() {}@Override public void method4() {}@Override public void method5() {}@Override public void method6() {}@Override public void method7() {}
}
// 3. 子类只重写自己需要的方法
public class MyListener extends InterAdapter {@Overridepublic void method3() {System.out.println("只处理 method3 的逻辑");}@Overridepublic void method7() {System.out.println("只处理 method7 的逻辑");}
}
接口的多态
-
接口定义行为规范
接口声明一组方法(抽象方法、默认方法、静态方法等),但不提供具体实现,例如:public interface Animal {void makeSound(); // 抽象方法(行为规范) }
-
不同类实现接口
多个类实现同一个接口,并各自提供方法的具体实现:public class Dog implements Animal {@Overridepublic void makeSound() {System.out.println("汪汪!");} }public class Cat implements Animal {@Overridepublic void makeSound() {System.out.println("喵喵~");} }
-
通过接口类型调用方法
使用接口类型的变量引用不同实现类的对象,调用方法时实际执行的是具体类的实现:public class Main {public static void main(String[] args) {Animal animal1 = new Dog(); // 接口引用指向Dog对象Animal animal2 = new Cat(); // 接口引用指向Cat对象animal1.makeSound(); // 输出:汪汪!animal2.makeSound(); // 输出:喵喵~} }
内部类
内部类的访问特点
- 内部类 → 外部类:
- 可以直接访问外部类的所有成员(包括私有属性和私有方法),无需创建对象。
- 示例:
Engine
类的show()
方法直接访问了Car
类的carName
属性。
- 外部类 → 内部类:
- 必须通过实例化内部类对象才能访问其成员。
- 示例:
Car
类的show()
方法通过Engine e = new Engine()
创建内部类对象,再调用e.show()
。
public class Car {String carName; // 外部类属性(默认包访问权限)int carAge;String carColor;public void show() {System.out.println(this.carName); // 访问外部类属性Engine e = new Engine(); // 实例化内部类e.show(); // 调用内部类方法}class Engine { // 内部类定义String engineName;int engineAge;public void show() {System.out.println(engineName); // 访问内部类属性System.out.println(carName); // 直接访问外部类属性}}
}
内部类的分类
成员内部类
-
定义在成员位置,属于外部类的成员
-
成员内部类可以被一些修饰符所修饰,比如: private,默认,protected,public,static
-
在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量
public class Car { String carName; int carAge; int carColor; private class Engine{ //成员内部类String engineName; int engineAge; } }
获取成员内部类对象的两种方式:
方式一:外部直接创建成员内部类的对象
外部类.内部类 变量 = new 外部类().new 内部类();
public class Test {public static void main(String[] args) {// 宿主:外部类对象。// Outer out = new Outer();// 创建内部类对象。Outer.Inner oi = new Outer().new Inner();oi.method();}
}
方式二:在外部类中定义一个方法提供内部类的对象
public class Outer {String name;private class Inner{//定义成私有外部无法直接获取static int a = 10;//jdk16开始才行定义为static}public Inner getInstance(){return new Inner();}
}public class Test {public static void main(String[] args) {Outer o = new Outer();//直接使用内部类System.out.println(o.getInstance());//使用Object(父类)来接收Object inner = o.getInstance();}
}
内部类访问外部类对象
创建内部类对象时,对象中有一个隐含的外部类名.this
记录外部类对象的地址值
内部类访问外部类对象的格式是:外部类名.this
public class Test {public static void main(String[] args) {Outer.inner oi = new Outer().new inner();oi.method();}
}class Outer { // 外部类private int a = 30;// 在成员位置定义一个类class inner {private int a = 20;public void method() {int a = 10;System.out.println(???); // 10 答案:aSystem.out.println(???); // 20 答案:this.aSystem.out.println(???); // 30 答案:Outer.this.a}}
}
静态内部类
public class Outer {//静态内部类static class Inner {//非静态方法public void show1() {System.out.println("非静态的方法被调用了");}//静态方法public static void show2() {System.out.println("静态的方法被调用了");}}
}
静态内部类特点:
-
静态内部类是一种特殊的成员内部类。
-
有static修饰,属于外部类本身的。
-
总结:静态内部类与其他类的用法完全一样。只是访问的时候需要加上外部类.内部类。
-
拓展1:静态内部类可以直接访问外部类的静态成员。
-
拓展2:静态内部类不可以直接访问外部类的非静态成员,如果要访问需要创建外部类的对象。
-
拓展3:静态内部类中没有Outer.this。
内部类的使用格式
外部类.内部类
(与其他静态类一致,只是加了个外部类)
静态内部类对象的创建格式
外部类.内部类 变量 = new 外部类.内部类构造器;
Outer.Inner oi = new Outer.Inner();
调用方法的格式:
- 调用非静态方法的格式:先创建对象,用对象调用
- 调用静态方法的格式:外部类名.内部类名.方法名();
public class Test {public static void main(String[] args) {//静态内部类只能访问外部类中的静态变量和静态方法,//如果想要访问非静态的需要创建外部类的对象//创建静态内部类对象的格式://外部类名.内部类名 对象名 = new 外部类名.内部类名();Outer.Inner oi = new Outer.Inner();//调用静态方法的格式:oi.show1();//不推荐//外部类名.内部类名.方法名();Outer.Inner.show2();}
}
局部内部类
- 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
- 外界是无法直接使用,需要在方法内部创建对象并使用。
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
class 外部类名 {数据类型 变量名;修饰符 返回值类型 方法名(参数列表) {// …class 内部类 {// 成员变量// 成员方法}}
}
匿名内部类【重点】
隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。
概述
实际上,如果我们希望定义一个只要使用一次的类,就可考虑使用匿名内部类。匿名内部类的本质作用是为了简化代码
匿名内部类 :是内部类的简化写法。他是一个隐含了名字的内部类。开发中,最常用到的内部类就是匿名内部类了。(也会被编译为一个class文件,名字为外部类$1,外部类$2…)
格式
new 类名或者接口名() {重写方法;
};//可以使用实现是接口或继承的类来接收这个匿名内部类的对象
包含了:
- 继承或者实现关系
- 方法重写
- 创建对象
所以从语法上来讲,这个整体其实是匿名内部类对象
interface Swim {public abstract void swimming();
}public class Demo07 {public static void main(String[] args) {// 使用匿名内部类new Swim() {@Overridepublic void swimming() {System.out.println("自由泳...");}}.swimming();// 接口 变量 = new 实现类(); // 多态,走子类的重写方法Swim s2 = new Swim() {@Overridepublic void swimming() {System.out.println("蛙泳...");}};s2.swimming();s2.swimming();}
}