回顾:
权限修饰符: public -> protected -> (default) ->private
重写:
1.方法名和参数列表一致
2.子类中重写的方法, 返回值类型[小于等于]父类返回值类型(如父类方法是public,子类就是public或是protected或是默认default)
3.权限修饰符,[大于等于]父类方法的权限
final:
类: 类不能被继承
方法: 方法不能被重写
变量: 常量, 不能被修改, 必须初始化
常见的final类:
String Math
String不可变的: CharSequence - 字符序列 - 字符数组
底层实现: 字符数组 -> 字节数组 byte[] value
final value = 其他值
String str = “hello”;
str = “hi”;
1.1 接口:
1.公共的抽象方法
2.公共的静态常量 public static final
3.公共的默认方法
4.公共的静态方法[私有的]
5.私有的方法
1.1.1使用接口:
实现类 implements 接口
实现所有的抽象方法, 默认方法[可以选择性重写]
创建实现类对象, 调用方法
①
类和接口叫做多实现, 要重写/覆盖[实现]所有的口的所有抽象方法和重复的默认方法
package Demo1001;
//接口类
public interface Interface01 {
void abstractmethod();
void abstractmethod01();
}
package Demo1001;
//实现类
public class Imply implements Interface01{
@Override
public void abstractmethod() {
System.out.println("001");
}
@Override
public void abstractmethod01() {
System.out.println("002");
}
}
②
类和类叫做单继承, 父类中的方法和父接口中的默认方法重复了, 优先调用父类中的方法:
Zi extends Fu implements InterfaceA
Fu和InterfaceA中的方法重名,优先调用Fu中的方法
③
接口作为方法参数, 接口作为返回值:
具体使用的都是接口的实现类对象
package Demo1001;
//主类
public class Demo1001 {
public static void main(String[] args) {
Imply impl = new Imply();
impl.abstractmethod();
impl.method01();
Demo10011 cc = new Demo10011();
cc.h(impl);
}
}
package Demo1001;
//接口作为返回参数
public class Demo10011{
public static Interface01 h(Interface01 a){
a.abstractmethod();
// Interface01 a1 = new Imply();
// return a1;
return new Imply();
}
}
package Demo1001;
//实现类
public class Imply implements Interface01{
Imply(){
System.out.println("OOO");
}
@Override
public void abstractmethod() {
System.out.println("001");
}
@Override
public void abstractmethod01() {
System.out.println("002");
}
}
package Demo1001;
//接口类
public interface Interface01 {
void abstractmethod();
void abstractmethod01();
public default void method01(){
System.out.println("AAA");
method03();
}
static void method03(){
System.out.println("BBB");
System.out.println("CCC");
}
}
//OOO
//001
//AAA
//BBB
//CCC
//001
//OOO
1.2多态的前提:
class MyInterfaceAImpl extends Object implmenets MyInterfaceA
MyInterfaceA a = new MyInterfaceAImpl() -> 向上造型
Object o = new MyInterfaceAImpl() -> 向上造型
Fu fu = new Zi();
Animal a = new Cat();
父类型引用 指向 子类型对象 -> 向上造型
父类型 a = new 子类型对象();
接口类型 a = new 实现类对象();
编译器 看 = 左边类型, 运行时JVM 看 = 右边类型
package Demo1002;
//主类
public class Main {
public static void main(String[] args) {
//父类型引用 指向 子类型
//Demo10Fu fu = new Demo10Fu();
Demo10Fu fu = new Dem10Zi();
Dem10Zi zi = (Dem10Zi) fu;
//Dem10Zi zi = new Dem10Zi();
fu.m1();
//编译看左边,fu中的变量
System.out.println(fu.age);
//运行看右边,子类中的重写方法
System.out.println(fu.getAge());
//fu.m3();
zi.m3();
fu.m4(zi);
}
}
package Demo1002;
//父类
public class Demo10Fu {
int age = 10;
public void m1(){
System.out.println("Fu m1方法");
}
public int getAge() {
return age;
}
public Demo10Fu m4(Demo10Fu a){
System.out.println("JJJ");
return null;
}
}
package Demo1002;
//子类
public class Dem10Zi extends Demo10Fu{
int age = 20;
public int getAge() {
return age;
}
public void m3(){
System.out.println("TTT");
}
}
//Fu m1方法
//10
//20
//TTT
//JJJ
左边类型决定了变量 能调用哪些方法,
右边类型决定了最终使用的方法是哪个 - 优先调用自己重写过的
口诀: 编译看左边, 运行看右边
1.2.1提前得知, 引用到底是什么类型的对象
上下转型,a1不进行强转,无法调用Cat类中的方法
package Demo1003;
//主类
public class Main {
public static void main(String[] args) {
//向上转型
Animal a1 = new Cat();
//向下转型
Cat a3 = (Cat)a1;
Animal a2 = new Dog();
Dog a4 = (Dog)a2;
a1.eat();
a3.catchMouse();
a2.eat();
a4.watchHouse();
getPet(a1);
getPet(a2);
salePet(a3);
salePet(a4);
}
//输出变量
public static Animal salePet(Animal t){
if(t instanceof Cat){
Cat n = (Cat)t;
System.out.println("买" + n.name);
}
else if(t instanceof Dog){
Dog n = (Dog)t;
System.out.println("买" + n.name);
}
else{
System.out.println();
}
return null;
}
//父类型作为返回值,功能扩展性更强,返回Animal类
public static void getPet(Animal n){
//n instanceof Ob,判断n是否是Ob类型的对象
if(n instanceof Cat){
System.out.print("买了只猫");
((Cat) n).catchMouse();
n.eat();
Cat ab = (Cat)n;
System.out.println(ab.name);
}
else if(n instanceof Dog){
System.out.print("买了只狗");
((Dog) n).watchHouse();
n.eat();
Dog ab = (Dog)n;
System.out.println(ab.name);
}
}
}
package Demo1003;
//父类
public abstract class Animal {
public abstract void eat();
String name = "宠物";
}
package Demo1003;
//Cat子类
public class Cat extends Animal{
String name = "猫";
public void catchMouse(){
System.out.println("抓老鼠");
}
@Override
public void eat() {
System.out.println("猫吃猫粮");
}
}
package Demo1003;
//Dog子类
public class Dog extends Animal{
String name = "狗";
public void watchHouse(){
System.out.println("看家");
}
@Override
public void eat() {
System.out.println("狗吃狗粮");
}
}
//猫吃猫粮
//抓老鼠
//狗吃狗粮
//看家
//买了只猫抓老鼠
//猫吃猫粮
//猫
//买了只狗看家
//狗吃狗粮
//狗
//买猫
//买狗
Animal -> abstract void eat()
Cat -> void catchMouse() {}
Dog -> void watchHouse() {}
多态: Animal a1 = new Cat();
Animal a2 = new Dog();
ClassCastException: 类型转换异常
解决方案: 转换之前先判断引用 实际上是不是要转换的类型对象
引用a instanceof 子类型 => boolean
问 a 实际上是不是子类型对象
1.3内部类:
1.3.1内部类示例
类中写个类
人体类 心脏类
车类 发动机类
种类: 成员内部类,静态内部类,局部内部类[匿名内部类]
成员内部类: 权限 public,protected,(default),private
语法:
public class Outer{
// …
public class Inner{
//…
}
}
使用:
内部类中, 可以随意使用外部类成员
外部类中, 使用内部类成员时需要创建内部类对象
无关类中, 使用内部类成员
1.间接调用, 在外部类方法中调用内部类方法
main方法中, 调用外部类方法
2.直接调用, 需要创建内部类对象
外部类.内部类 a = new 外部类().new 内部类();
内部类和外部类有同名成员变量
外部类的成员变量: 外部类.this.变量
内部类的成员变量: this.变量
package Demo1004;
//主类
public class Main {
public static void main(String[] args) {
//在无关类中使用Body内部的Heart
Body body = new Body();
System.out.println(body.a);
//间接调用内部类,walk中有内部类
body.walk();
//直接调用内部类
Body.Heart heart = body.new Heart();
heart.beat();
//调用内部变量
System.out.println(heart.num);
System.out.println(heart.a);
//内部类中内部类的调用
Body.Heart.Heart1 heart1 = heart.new Heart1();
heart1.beat1();
}
}
package Demo1004;
public class Body {
int a = 10;
//外部类的方法
public void walk(){
System.out.println("跑步");
//外部类中直接创建内部对象
Heart heart = new Heart();
heart.beat();
//外部类使用内部类变量不能直接调用,需要内部类对象
System.out.println(heart.num);
}
//成员内部类:成分和外部类一样
public class Heart{
int num = 5;
int a = 20;
public void beat(){
//如果内部类中没有定义a,内部类可以使用外部类的变量
//System.out.println("心脏跳动" + a);
//使用内部类的变量a
System.out.println("心脏跳动" + a);
//内部和外部的变量重名,内部类使用外部类的变量的方法
System.out.println("心脏跳动" + Body.this.a);
//内部类不能调用外部类,不然会无限循环
}
//在内部类中定义内部类
public class Heart1{
public void beat1(){
System.out.println("心脏跳动更快了");
}
}
}
}
//10
//跑步
//心脏跳动20
//心脏跳动10
//5
//心脏跳动20
//心脏跳动10
//5
//20
//心脏跳动更快了
1.3.2局部内部类:
在方法内部定义类, 只在方法中有效
在局部内部类中, 使用局部变量, 必须是final的
JDK8 后, 局部变量事实上没有发生改变, 那么final可以省略
一次性的类, 只能用一次
不能使用权限修饰符
局部内部类, 需要类只使用一次, 优化 -> 匿名内部类
package Demo1005;
public class Outer {
int b = 20;
public void m1(){
int a = 10;
//局部内部类不能使用权限修饰符
class Inner{
public void innerM1(){
System.out.println("局部内部类M1" + a);
System.out.println("成员变量b:"+ b);
}
}
Inner i =new Inner();
i.innerM1();
}
public void m2(){
int a = 10;
class Inner{
}
}
}
package Demo1005;
public class Main {
public static void main(String[] args) {
Outer out = new Outer();
out.m1();
}
}
//局部内部类M110
//成员变量b:20
1.3.3匿名内部类:
继承抽象类或实现接口
语法: new 接口/抽象类() {
int a;
// 实现的所有抽象方法
}
匿名内部类, 只能用一次, new一个对象
匿名对象, 只能使用一次, 只能调用一次方法
注意: 匿名内部类 和 匿名对象 不是一回事 ! ! !
package Demo1006;
//主类
public class Outer {
public static void main(String[] args){
//使用接口的方法
//局部内部类
InterFaceA impl = new InterFaceA() {
@Override
public void method() {
System.out.println("内部类实现1");
}
@Override
public void method01() {
System.out.println("内部类实现2");
}
};
impl.method();
impl.method01();
//匿名内部类
InterFaceA impl1 = new InterFaceA()
{
@Override
public void method() {
System.out.println("内部实现类01");
}
@Override
public void method01() {
System.out.println("内部实现类02");
}
};
impl1.method();
impl1.method01();
}
}
package Demo1006;
//实现类
public class InterImply implements InterFaceA{
@Override
public void method() {
}
@Override
public void method01() {
}
}
package Demo1006;
//接口类
public interface InterFaceA {
void method();
void method01();
}
//内部类实现1
//内部类实现2
//内部实现类01
//内部实现类02
静态内部类 对比 成员内部类 => 静态方法 和 成员方法