面向对象编程JAVA(高级部分)

编程入门 行业动态 更新时间:2024-10-10 17:23:30

<a href=https://www.elefans.com/category/jswz/34/1769334.html style=面向对象编程JAVA(高级部分)"/>

面向对象编程JAVA(高级部分)

文章目录

  • 类变量和类方法
    • 类变量
    • 类方法/静态方法
  • main方法
    • main动态传值
  • 代码块/初始化块
    • 语法+概念
    • 代码块的好处:
    • 代码块细节
      • 类什么时候被加载?*
      • 创建一个对象时,在一个类调用顺序(重点、难点)
      • 创建一个子类时(继承关系),他们的静态代码块、静态属性初始化、普通代码块、普通属性初始化、构造方法的调用顺序(难点、面试题)
      • 练习
  • 单例设计模式
    • 设计模式的概念
    • 单例模式
    • 单例模式饿汉类
    • 单例模式懒汉类
      • 饿汉式与懒汉式区别
  • final关键字
    • 应用场景
    • 使用细节
  • 抽象类
    • 概念
    • 介绍
    • 使用细节
    • 抽象——模板设计模式
  • 接口
    • 快速入门
    • 基本介绍
    • 应用场景
    • 使用细节
    • 接口VS继承
    • 接口多态特性
      • 多态参数
      • 多态数组
      • 多态传递
    • 练习
  • 内部类(非常重要、难点)
    • 局部内部类
    • 匿名内部类(重点、难点)
      • 演示基于接口匿名内部类的使用
      • 演示基于类匿名内部类的使用
      • 使用细节
      • 匿名内部类的最佳实践
        • 练习一
        • 练习二
    • 成员内部类
    • 静态内部类

类变量和类方法

类变量

也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。

JDK8之前,静态变量存储在常量池中;JDK8以后,保存在class实例的尾部,而class对象存在于堆中。


public class ChildGame {public static void main(String [] args) {int count = 0;Child child1 = new Child("白骨精");child1.join();child1.count++;Child child2 = new Child("狐狸精");child2.join();child2.count++;Child child3 = new Child("老鼠精");child3.join();child3.count++;//类变量可以通过类名来访问System.out.println("共有" + Child.count + "个小孩加入了游戏!");//白骨精加入了游戏!//狐狸精加入了游戏!//老鼠精加入了游戏!//共有3个小孩加入了游戏!System.out.println("==========================================");System.out.println("child1.count=" + child1.count);System.out.println("child2.count=" + child2.count); System.out.println("child3.count=" + child3.count);//child1.count=3//child2.count=3//child3.count=3		}	
}
class Child {private String name;//定义一个变量count,是一个类变量(静态变量)static//该变量最大的特点是会被child类的所有对象实例共享。public static int count = 0;public Child(String name) {this.name = name;}public void join() {System.out.println(name + "加入了游戏!");}
}
  1. 语法:访问修饰符 static 数据类型 变量名
  2. 如何访问?
  • 对象名.类变量名【静态变量的访问修饰符的访问权限和范围和普通属性是一样的】
  • 类名.类变量名(推荐使用)
public class VisitStatic {public static void main(String [] args) {//类名.类变量名//说明:类变量是随着类的加载而创建的,所以即使没有创建对象实例也可以访问。System.out.println(A.name);//对象名.类变量名A a = new A();System.out.println(a.name);}
}
class A {//类变量//类变量的访问必须遵守相关的访问权限,这里是publicpublic static String name = "郭泳妍";
}============================================================================public class VisitStatic {public static void main(String [] args) {//类名.类变量名//说明:类变量是随着类的加载而创建的,所以即使没有创建对象实例也可以访问。System.out.println(A.getName());//对象名.类变量名A a = new A();System.out.println(a.getName());}
}
class A {//类变量//类变量的访问必须遵守相关的访问权限,这里是publicprivate static String name = "郭泳妍";public static String getName() {return name;}public static void setName(String name) {A.name = name;}
}
  1. 当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量。
  2. 类变量与实例变量的区别:类变量是该类的所有对象共享的,实例变量是每个对象独享的。
  3. 加上static称为类变量或者静态变量,否则称为实例变量/普通变量/非静态变量。
  4. 类变量在加载时就已经被初始化,意思是即使没有创建对象,只要类加载了就可以使用类变量。
  5. 类变量的生命周期是随着类的加载开始的,随着类的消亡而销毁。

类方法/静态方法

  1. 语法:访问修饰符 static 数据返回类型 方法名() { }
  2. 如何调用?
  • 类名.类方法.
  • 对象名.类方法名【前提是满足访问修饰符的访问权限和范围】
public class StaicMethod {public static void main(String [] args) {//对象名.类方法名Stu tom = new Stu("tom");//tom.pay(1000);Stu.pay(1000);  //两种方法均可以Stu mary = new Stu("mary");mary.pay(2000);//类名.类方法//输出当前收到的总学费Stu.show();       //总学费有3000.0}
}
class Stu {private String name;//定义一个静态变量来累计学生学费private static double fee = 0;public Stu() {super();}public Stu(String name) {super();this.name = name;}//当方法使用了static修饰后,该方法为静态方法public static void pay(double fee) {Stu.fee += fee;  //累计到静态变量的fee}public static void show() {System.out.println("总学费有" + Stu.fee);}
}
  1. 经典使用场景:当方法中不涉及到任何和对象有关的成员,即不创建实例也可以调用某个方法(也就是说当成工具使用),则可以将方法设计成静态方法提升开发效率。
System.out.println("9开方的结果是:" + Math.sqrt(9));
  1. 开发自己的工具时,可以将方法做成静态的,方便进行调用。
  2. 类方法和普通方法都是随着类的加载而加载的,将结构信息存储在方法区中。
  3. 类方法中无this这个参数,而普通方法中隐含着this这个参数。
  4. 类方法可以通过类名和对象名来调用。
  5. 普通方法和对象有关,需要通过对象名来调用,比如对象名.方法名(参数),不能通过类名调用。
  6. 类方法中不允许使用和对象有关的关键字,如this、super,而普通方法可以。
  7. 类方法中只能访问静态变量或者静态方法。
  8. 普通成员既可以访问普通变量,也可以访问静态变量。
  9. 静态方法只能访问静态的成员;非静态的方法,可以访问静态成员和非静态成员。
class D {private int n1 = 100;private static int n2 = 200;public void say() {}public static void hi() {//类方法中不允许使用和对象有关的关键字,如`this、super//System.out.println(this.n1);}public static void hello() {//System.out.println(D.n1);     ---->报错System.out.println(n2);System.out.println(D.n2);//System.out.println(this.n2);   ---->报错hi();//say();       ---->报错}//静态方法只能访问静态的成员;非静态的方法,可以访问静态成员和非静态成员。public void OK() {//非静态成员System.out.println(n1);say();//静态成员System.out.println(n2);hi();hello();}
}

main方法

  1. 语法:
public static void main(String [] args)
  1. Java虚拟机需要调用类的main方法,所以该方法的访问权限必须要是public,否则运行不了。
  2. java虚拟机在执行main方法时不必创建对象,作为程序入口,所以该方法必须是static
  3. 该方法接收Sting类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。
  4. main()方法中,可以直接调用main方法所在类的静态方法和静态属性。
  5. 但是,不能直接访问该类中的非静态成员,必须创建一个实例对象后才可以访问。
public class Main01 {//静态变量/属性private static String name = "郭泳妍";//静态方法public static void hi() {System.out.println("hi!");}//非静态属性private int n1 = 100;//非静态方法public void cry() {System.out.println("喵喵喵……");}public static void main(String[] args) {// TODO Auto-generated method stub//可以直接使用name,静态方法可以访问本类的静态成员System.out.println(name);  //郭泳妍hi();//静态方法不可以访问本类的非静态成员和非静态方法//System.out.println(n1);     ----->报错//cry();       ----->报错//要访问需要先创建实例对象再调用Main01 main01 = new Main01();main01.hi();main01.cry();}}

main动态传值

不同的编译器和不同的版本在网上查询教程。

代码块/初始化块

语法+概念

  1. 属于类中的成员,类似于方法,将逻辑语句封装在方法体中,通过{ }包围起来。
  2. 但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是记载类时,或者创建对象时隐式调用。
  3. 基本语法:

[修饰符] {
代码
};

注意

  • 修饰符可选,要写的话只能写static
  • 代码块分两类,使用static修饰的叫静态代码块,没有static修饰的叫做普通代码块/非静态代码块。
  • 逻辑语句可以分为任意逻辑语句。
  • ;可以写上,也可以省略。

代码块的好处:

  1. 相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作。
  2. 应用场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码重用性。
  • 三个构造器中都要有相同的输出语句,这时可以把相同的语句放入一个代码块中即可。
  • 这样当我们不管调用哪个构造器,创建对象都会先调用代码块内容。
  • 代码块调用的顺序优先于构造器。
public class CodeBlock01 {public static void main(String[] args) {// TODO Auto-generated method stubMovie movie1 = new Movie("你好李焕英");Movie movie2 = new Movie("你好李焕英","贾玲");}}
class Movie {private String name;private String director;private double price;//3个构造器  ------>重载//三个构造器中都要有相同的输出语句,这时可以把相同的语句放入一个代码块中即可。//这样当我们不管调用哪个构造器,创建对象都会先调用代码块内容。//代码块调用的顺序优先于构造器。{System.out.println("电影屏幕打开");System.out.println("广告开始");System.out.println("电影正式开始");   }public Movie(String name) {super();
//		System.out.println("电影屏幕打开");
//		System.out.println("广告开始");
//		System.out.println("电影正式开始");   System.out.println("public Movie(String name)被调用");this.name = name;}public Movie(String name, String director) {super();this.name = name;this.director = director;System.out.println("public Movie(String name, String director)被调用");}public Movie(String name, String director, double price) {super();this.name = name;this.director = director;this.price = price;}	
}============================================================================电影屏幕打开
广告开始
电影正式开始
public Movie(String name)被调用
电影屏幕打开
广告开始
电影正式开始
public Movie(String name, String director)被调用

代码块细节

static代码块也叫静态代码块,作用就是对类进行初始化,而且他随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象就执行一次。

类什么时候被加载?*

  • 创建对象时实例化(new)。
  • 创建子类对象实例,父类也会被加载。
  • 使用类的静态成员时(静态属性,静态方法)

普通的代码块,在创建对象实例时被隐式调用,对象被创建一次,就会被调用一次;而如果只是使用类的静态成员时,普通代码块并不会执行。

public class CodeBlock02 {public static void main(String[] args) {// TODO Auto-generated method stub//创建对象实例时(new)AA a1 = new AA();      //AA的静态代码块被执行!//创建子类对象实例,父类也会被加载。//先加载父类,再加载子类AA a2 = new AA();      //BB的静态代码块被执行!   AA的静态代码块被执行!//使用类的静态成员时(静态属性,静态方法)//调用静态成员时,只有static代码块会被执行,普通代码块不会被执行System.out.println(Cat.n1);     //Cat的第一次静态代码块被执行!   Cat的第三次静态代码块被执行!  100//即使创建对象,static静态代码块只会被执行一次DD dd1 = new DD();DD dd2 = new DD();     //DD的静态代码块被执行!}}
class DD {static {System.out.println("DD的静态代码块被执行!");}
}
class Cat {public static int n1 = 100;static {System.out.println("Cat的第一次静态代码块被执行!");}{System.out.println("Cat的第二次静态代码块被执行!");}static {System.out.println("Cat的第三次静态代码块被执行!");}
}
class BB  {static {System.out.println("BB的静态代码块被执行!");}
}
class AA extends BB{//静态代码块static {System.out.println("AA的静态代码块被执行!");}
}

创建一个对象时,在一个类调用顺序(重点、难点)

  1. 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化块调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们的定义顺序调用)。
  2. 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和普通属性初始化则按他们的定义顺序调用)
  3. 调用构造方法
public class CodeBlock03 {public static void main(String[] args) {// TODO Auto-generated method stub//1. 静态代码块和静态属性初始化块调用的优先级一样,//如果有多个静态代码块和多个静态变量初始化,则按他们的定义顺序调用//2. 普通代码块和普通属性初始化调用的优先级一样,//如果有多个普通代码块和普通属性初始化则按他们的定义顺序调用A a = new A();   //1.getN1()被调用……  2. A 静态代码块被调用……//3.getN2()被调用……  4.A 普通代码块被调用……//5.A构造器被调用…				 }}
class A {public A() {System.out.println("A构造器被调用……");}//普通属性初始化private int n2 = getN2();//普通代码块{System.out.println("A 普通代码块被调用……");}//静态属性初始化private static int n1 = getN1();//静态代码块static {System.out.println("A 静态代码块被调用……");}public static int getN1() {System.out.println("getN1()被调用……");return 100;}public int getN2() {System.out.println("getN2()被调用……");return 200;}
}============================================================================getN1()被调用……
A 静态代码块被调用……
getN2()被调用……
A 普通代码块被调用……
A构造器被调用……

构造器的最前面其实隐含了super()和调用普通代码块,静态相关的代码块、属性初始化,在类加载时就执行完毕,因此是优先于构造器和普通代码块执行的。

public class CodeBlock04 {public static void main(String[] args) {// TODO Auto-generated method stubAAA  a = new B(); //AAA普通代码块被调用   AAAA()构造器被调用、//BBB普通代码块被调用、  B()构造器被调用}}
class AAA {public AAA() {//隐藏的执行要求://1.super(); ---->继承讲解//2. 调用普通代码块System.out.println("AAA()构造器被调用");}{System.out.println("AAA普通代码块被调用");}
}
class B extends AAA{public B () {System.out.println("B()构造器被调用");}{System.out.println("BBB普通代码块被调用");}
}===================================================================================
AAA普通代码块被调用
AAA()构造器被调用
BBB普通代码块被调用
B()构造器被调用

创建一个子类时(继承关系),他们的静态代码块、静态属性初始化、普通代码块、普通属性初始化、构造方法的调用顺序(难点、面试题)

  • 父类的静态代码块和静态属性(优先级相同,按定义顺序调用)。
  • 子类的静态代码块和静态属性(优先级相同,按定义顺序调用)。
  • 父类的普通代码块和普通属性初始化(优先级相同,按定义顺序调用)。
  • 父类的构造方法。
  • 子类的普通代码块和普通属性初始化(优先级相同,按定义顺序调用)。
  • 子类的构造方法。

练习

静态代码块可以只能调用静态成员,普通代码块可以调用任意成员。

单例设计模式

设计模式的概念

  1. 静态方法和属性的经典使用。
  2. 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。

单例模式

就是采用一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

单例模式饿汉类

类被加载后即全部对象都创建【创建后未被利用,可能造成资源浪费】

  • 构造器私有化(防止直接new对象)
  • 类的内部创建对象。
  • 向外暴露一个静态的公共方法。
  • 代码实现。

/**  构造器私有化(防止直接`new`对象)*  类的内部创建对象。*  向外暴露一个静态的公共方法。*  代码实现。*///单例模式保证一个类只能创建一个对象
public class TestSingleton {public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1 == s2);   //true}}
class Singleton {//本类类型的静态私有变量//为了能够在静态方法中将私有的inatance返回,需将其修饰为staticprivate static Singleton instance;//构造器私有化private Singleton() {System.out.println("Singleton()无参构造器被调用……");}//静态的公共方法public static Singleton getInstance() {if(instance == null) {//类的内部创建对象。instance = new Singleton();}return instance;}
}===================================================================================Singleton()无参构造器被调用……
true

单例模式懒汉类

即类中的对象被使用后才会被创建

//懒汉式public class TestSingleton02 {public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println(Cat.n1);   // 100【构造器未被调用】Cat instance1 = Cat.getInstance();System.out.println(instance1);    //构造器被调用     Cat [name=小可爱]Cat instance2 = Cat.getInstance();System.out.println(instance2);    //Cat [name=小可爱],cat已经不是空System.out.println(instance1 == instance2);   //true}}//希望程序在运行过程中,只能创建一个cat对象
//使用单例模式
class Cat {private String name;	public static int n1 = 100;private static Cat cat;  //默认是nullprivate Cat(String name) {System.out.println("构造器被调用");this.name = name;}//懒汉式中,只有当用户使用getInstance() 时才会返回cat对象,//后面再次调用时返回上次创建的cat对象//从而保证了单例public static Cat getInstance() {if(cat == null) {cat = new Cat("小可爱");}return cat;}@Overridepublic String toString() {return "Cat [name=" + name + "]";}}===================================================================================100
构造器被调用
Cat [name=小可爱]
Cat [name=小可爱]
true

饿汉式与懒汉式区别

  • 最主要的区别在于创建对象的时机不同:饿汉式是类加载时就创建了对象实例,而懒汉式是在使用时才创建。
  • 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
  • 饿汉式存在浪费资源的可能。

final关键字

final可以修饰类、属性、方法、局部变量。

应用场景

  1. 当不希望类被继承时,可以用final修饰。
  2. 但不希望父类的某个方法被子类覆盖或者重写时,可以用final关键字修饰。
public final void hi(){}
  1. 当不希望类的某个属性的值被修改但是仍然可以调用。
public final double TAX = 0.09;
  1. 当不希望某个局部变量被修改。
public class Final01 {public static void main(String[] args) {// TODO Auto-generated method stub}}//当不希望A类被继承时,可以用final修饰A类。
final class A {}
//class B extends A {}class C {// 但不希望hi方法被子类覆盖或者重写时,可以用final关键字修饰hi方法。public void hi() {};//public final void hi(){}
}
class D extends C {@Overridepublic void hi() {// TODO Auto-generated method stubsuper.hi();System.out.println("重写了C类的hi方法");}}

使用细节

  1. final修饰的属性又叫常量,一般字母全部是大写,且字母用下划线隔开。如TAX_NUM
  2. final修饰的属性在定义时必须赋初值,并且以后不能再修改,赋值可以在如下位置之一:
  • 定义时:public final double TAX_RATE = 0.08;
  • 在构造器中。
  • 在代码块中。
class AA {public final double TAX_RATE1 = 0.09;      //定义时public final double TAX_RATE2;public final double TAX_RATE3;public AA () {TAX_RATE2 = 0.02;         //在构造器中}{TAX_RATE3 = 0.01;         //在代码块中}
}
  1. 如果final修饰的属性是静态的,则初始化的位置只能是:
  • 定义时
  • 在静态代码块中,不能再构造器中赋值
class BB {public static final double TAX_RATE1 = 0.09;    //定义时public static final double TAX_RATE2;public final double TAX_RATE3;	
//	public static final double TAX_RATE3;public BB () {TAX_RATE3 = 0.01;          //不能在构造器中}static {TAX_RATE2 = 0.02;          //在静态代码块中}}
  1. final类不能继承,但是可以实例化对象。
CC cc = new CC()
  1. 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承,可以在主类中创建对象时调用。
  2. 一般来说,如果一个已经是final类,就没有必要将方法修饰成final方法。
  3. final和static往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理。
public class Final02 {public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println(DD.num1);    //100System.out.println(DD.num2);    //DD静态代码块被执行  200} }
class DD {public final static int num1 = 100;public static int num2 = 200;static {System.out.println("DD静态代码块被执行");}
}	
  1. 包装类(Interger、Double、Float、Boolean等都是final),String类也是final类,这些都布不能被继承。

抽象类

概念

  1. 当父类的某个方法需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类。
  2. 当一个类中存在抽象方法时,需要将该类声明为abstract类。
  3. 一般来说抽象类会被继承,由其子类实现抽象方法。

介绍

  1. abstract修饰的类就是抽象类。

访问修饰符 abstract 类名 {

}

  1. abstract修饰的方法就是抽象方法。

访问修饰符 abstract 返回类型 方法名 (参数列表); //没有方法体

  1. 抽象类的价值更多在于设计,是设计师设计好后,让子类继承并实现抽象类。
  2. 抽象类在面试中常见。

使用细节

  1. 抽象类不能实例化。
  2. 抽象类不一定包含抽象方法,还可以有实现方法。
  3. 一旦类包含了abstract方法,则这个类必须声明为abstract
  4. abstract 只能修饰类和方法,不能修饰属性和其他的。
  5. 抽象类还是类,可以有任意成员,比如:非抽象方法、构造器、静态属性等等。
  6. 抽象方法不能有主体,即不能实现。【没有方法体】
  7. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非他自己也声明为abstract类。【所谓实现方法,就是要有方法体】。
  8. 抽象方法不能使用private、final、static修饰,因为这些关键字都是和重写相违背的。
abstract class A {public abstract void hi();	
}
//如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非他自己也声明为abstract类。
abstract class B extends A {}
class C extends A {@Overridepublic void hi() {// TODO Auto-generated method stubSystem.out.println("你好!");}	
}

抽象——模板设计模式

常见需求:

  1. 有多个类,完成不同的任务job
  2. 要求统计得到各自完成任务的时间。
public class T2 {public static void main(String[] args) {// TODO Auto-generated method stubAA a = new AA();a.job();}}
class AA {//计算任务:1到100的和public void job() {//得到开始时间long start = System.currentTimeMillis();long sum = 0;for(long i = 1; i<=900000;i++) {sum += i;}//得到结束时间long end = System.currentTimeMillis();System.out.println("运行时间:" + (end - start));}
}
class BB {public void job2() {//得到开始时间long start = System.currentTimeMillis();long sum = 0;for(long i = 1; i<=700000;i++) {sum += i;}//得到结束时间long end = System.currentTimeMillis();System.out.println("运行时间:" + (end - start));}
}===================================================================================
public class T3 {public static void main(String[] args) {// TODO Auto-generated method stubAAA a = new AAA();a.calculateTime();BBB b = new BBB();b.calculateTime();}}
abstract class Template {public abstract void job();  //抽象方法public void calculateTime() {long start = System.currentTimeMillis();job();   //动态机制绑定long end = System.currentTimeMillis();System.out.println("运行时间:" + (end - start));}
}
class AAA extends Template {@Overridepublic void job() {   //实现抽象方法long sum = 0;for(long i = 1; i<=900000;i++) {sum += i;}}
}
class BBB extends Template {@Overridepublic void job() {   //实现抽象方法long sum = 0;for(long i = 1; i<=800000;i++) {sum += i;}}
}
==================================
运行时间:3
运行时间:2

接口

USB插槽就是现实中的接口。

快速入门

public class Interface01 {public static void main(String[] args) {// TODO Auto-generated method stubCamera camera = new Camera();Phone phone = new Phone();Computer1 computer1 = new Computer1();computer1.work(phone);  //把手机接入计算机computer1.work(camera);}}
interface UsbInterface {//规定接口的相关方法public void start();public void stop();
}//phone类实现UsbInterface
class Phone implements UsbInterface {@Overridepublic void start() {// TODO Auto-generated method stubSystem.out.println("手机开始工作");}@Overridepublic void stop() {// TODO Auto-generated method stubSystem.out.println("手机停止工作");}}
//camera类实现UsbInterface
class Camera implements UsbInterface {@Overridepublic void start() {// TODO Auto-generated method stubSystem.out.println("相机开始工作");}@Overridepublic void stop() {// TODO Auto-generated method stubSystem.out.println("相机停止工作");}
}
class Computer1 {public void work(UsbInterface usbInterface) {//通过接口调用方法usbInterface.start();usbInterface.stop();}
}==================================手机开始工作
手机停止工作
相机开始工作
相机停止工作

基本介绍

  1. 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
  2. 语法:

interface 接口名 {
//属性
//方法
}
class 类名 implements 接口 {
自己属性;
自己方法;
必须实现的接口的抽象方法
}

  1. JDK7之前接口的所有方法都没有方法体,即都是抽象方法。
  2. JDK8之后接口类可以有静态方法和默认方法,也就是说接口中可以有方法的具体实现。
interface AInterface {//属性public int n1 = 10;//方法public abstract void hello();    //抽象方法//接口中抽象方法可以省略abstractpublic void hello1();//JDK8之后接口类可以有静态方法和默认方法,也就是说接口中可以有方法的具体实现。default public void OK() {       //默认实现静态方法System.out.println("OK!");} public static void cry {       //静态方法System.out.println("喵喵喵……");}
}
class D implements AInterface {@Overridepublic void hello() {// TODO Auto-generated method stub}@Overridepublic void hello1() {// TODO Auto-generated method stub}}

应用场景

  1. 现在要制作战斗机,专家只需要把飞机需要的功能、规格定下来即可让别的人具体实现。

使用细节

  1. 接口不能被实例化。
  2. 接口中所有的方法是public方法,接口中的抽象方法可以不用abstract修饰。

void aaa(); = abstract void aaa();

  1. 一个普通类实现接口,就必须将接口中的所有方法都实现。
  2. 抽象类实现接口,可以不用实现接口的方法。
  3. 一个类同时可以实现多个接口。【单一继承】

class Pig implements IB,IC {
}

  1. 接口中的属性只能是final,而且是public static final修饰符。

int a =1 等价于
public static final int a = 1

  1. 接口中属性的访问形式:接口名.属性名。
  2. 一个接口不能继承其他的类,但是可以继承多个别的接口。

interface A extends B,C { //A、B、C均为接口
}

  1. 接口的修饰符只能是public和默认,这点和类相同。

接口VS继承

  1. 继承:当子类继承父类,就自动拥有了父类的功能
  2. 接口——补充机制:如果子类需要扩展功能,可以通过实现接口的方式扩展,可以理解为接口实际上是对java单继承机制的补充。
  3. 接口的价值在于设计规范好的方法,让其他类去实现;而继承的价值在于解决代码的复用性和可维护性。
  4. 接口比继承更加灵活,继承满足is-a的关系,接口满足like-a的关系。
  5. 接口在一定程度上实现了代码解耦(即接口规范性+动态绑定)
    高内聚低耦合
public class ExtendVSInterface {public static void main(String[] args) {// TODO Auto-generated method stubLittleMonkey wukong = new LittleMonkey("悟空");wukong.climbing();wukong.swimming();}}
class Monkey {private String name;public void climbing() {System.out.println( name + "猴子会爬树……");}public Monkey(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
//接口——补充机制:如果子类需要扩展功能,可以通过实现接口的方式扩展
//可以理解为接口实际上是对java单继承机制的补充
interface Fish {void swimming();
}
//继承:当子类继承父类,就自动拥有了父类的功能
class LittleMonkey extends Monkey implements Fish{public LittleMonkey(String name) {super(name);// TODO Auto-generated constructor stub}@Overridepublic void swimming() {// TODO Auto-generated method stubSystem.out.println( getName() + "猴子通过学习,向小鱼学会了游泳……");}}

接口多态特性

多态参数

前面的USB接口中,形参UsbInterface usbInterface既可以接收手机对象,也可以接收相机对象,就体现了接口多态。(接口引用可以指向实现了接口的类的对象)


```python
public class Interface01 {public static void main(String[] args) {// TODO Auto-generated method stubCamera camera = new Camera();Phone phone = new Phone();Computer1 computer1 = new Computer1();computer1.work(phone);  //把手机接入计算机computer1.work(camera);}}
interface UsbInterface {//规定接口的相关方法public void start();public void stop();
}//phone类实现UsbInterface
class Phone implements UsbInterface {@Overridepublic void start() {// TODO Auto-generated method stubSystem.out.println("手机开始工作");}@Overridepublic void stop() {// TODO Auto-generated method stubSystem.out.println("手机停止工作");}}
//camera类实现UsbInterface
class Camera implements UsbInterface {@Overridepublic void start() {// TODO Auto-generated method stubSystem.out.println("相机开始工作");}@Overridepublic void stop() {// TODO Auto-generated method stubSystem.out.println("相机停止工作");}
}
//UsbInterface usbInterface形参是接口类型
//这个参数实现了接口的类的对象实例
class Computer1 {public void work(UsbInterface usbInterface) {//通过接口调用方法usbInterface.start();usbInterface.stop();}
}

多态参数

多态数组

多态数组

多态传递

public class Interface04 {public static void main(String[] args) {// TODO Auto-generated method stub//接口类型的变量可以指向实现了该接口的类的对象实例IG ig = new Teacher();IH ih = new Teacher();  //Teacher并未实现IH接口//但如果IH继承IG,即Teacher可实现IH接口,体现了多态传递}}
interface IH {void hi();
}
interface IG extends IH{}
class Teacher implements IG {@Overridepublic void hi() {// TODO Auto-generated method stub}	
}

练习

public class Interface05 {public static void main(String[] args) {// TODO Auto-generated method stubnew C().px();}}
interface A {int x = 0;   //等价于 public static final int x = 0
}
class B {int x = 1;   //普通数学
}
class C extends B implements A {public void px() {//System.out.println(x);   //报错,不清楚哪个xSystem.out.println(A.x+""+super.x);  //访问父类x不可使用B.x}
}

内部类(非常重要、难点)

  1. 一个类的内部嵌套了另一个类结构,被嵌套的类称为内部类,嵌套其他类的类称为外部类。
  2. 类的五大成员:属性、方法、构造器、代码块、内部类。
  3. 内部类最大的特点是可以直接访问私有属性,并且体现类与类之间的包含关系。
  4. 内部类的分类:
    • 局部内部类(有类名)-------->定义在外部类的局部位置(比如方法内);
    • 匿名内部类(没有类名,重点)-------->定义在外部类的局部位置;
    • 成员内部类(没有static修饰)------->定义在外部类的成员位置;
    • 静态内部类(有static修饰)------->定义在外部类的成员位置;

局部内部类

1. 局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
2. 可以直接访问外部类的所有成员,包括私有的。
3. 不能添加访问修饰符,因为他的地位就是一个局部变量,局部变量不能使用修饰符。但是可以使用final修饰。 final修饰意味着局部内部类不能被继承,不加final意味着局部内部类可以被继承。
4. 局部内部类的作用域仅仅在定义它的方法或代码块中。
4. 局部内部类可以直接访问外部类的成员。
5. 外部类方法中,可以创建局部内部类对象然后调用方法即可。
6. 本质上还是一个类,即类的五大成员都可以有。
6. 外部其他类不能访问局部内部类(因为局部内部类的地位就是一个局部变量)。
7. 如果外部类和局部内部类的成员重名时,默认.就近原则,如果想访问外部类的成员,则可以使用外部类名.this.成员去访问。


//演示局部内部类的使用
public class LocalInnerClass {public static void main(String[] args) {// TODO Auto-generated method stubOuter02 outer02 = new Outer02();outer02.m1();}}
class Outer02 {   //外部类private int n1 =100;private void m2() {System.out.println("outer02 m2()");}  //私有方法public void m1() {  //方法//1. 局部内部类是定义在外部类的局部位置,通常在方法//3. 不能添加修饰符,但是可以使用final修饰。//4. 局部内部类的作用域仅仅在定义它的方法或代码块【本质是没有方法名的方法】中。//即该内部类的作用域为m1()方法中。final class Inner02 { //局部内部类,本质仍然是类,即五大成员都可以有。//可以直接访问外部类的所有成员,包括私有的private int n1 = 800;public void f1() { //5. 局部内部类可以直接访问外部类的成员,比如下面的外部类n1和m2()。//7. 如果外部类和局部内部类的成员重名时,默认.就近原则,如果想访问外部类的成员,//则可以使用`外部类名.this.成员`去访问//outer02.this本质上就是外部类的对象即哪个对象调用了m1方法,outer02.this就是哪个对象。System.out.println("内部类的n1=" + n1 + "外部类的n1=" + Outer02.this.n1);m2();   //也可直接访问私有方法}}//6. 外部类方法中,可以创建Inner02对象然后调用方法即可Inner02 inner02 = new Inner02();inner02.f1();}
}

匿名内部类(重点、难点)

匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名。
本质上是类。
内部类。
该类没有名字。
同时还是一个对象。

  1. 基本语法:

new 类或接口(参数列表){
类体
};

演示基于接口匿名内部类的使用

//演示基于接口匿名内部类的使用
public class Inner01 {    //外部其他类public static void main(String[] args) {// TODO Auto-generated method stubOuter01 outer01 = new Outer01();outer01.method();}}
class Outer01 {   //外部类private int n1 = 10;public void method() {//1. 基于接口的匿名内部类//2. 需求1:想使用接口A,并创建对象。//3. 传统方法:写一个类,实现该接口并创建对象
//		A tiger = new Tiger();
//		tiger.cry();//4. 需求2:tiger只是使用一次,后面不再使用。//5. 可以使用匿名内部类来简化开发//6. tiger的编译类型A ,运行类型是匿名内部类,底层分布随机类名Outer01$1,底层是实现关系//7. JDK底层在创建匿名内部类Outer01$1,立马就创建了Outer01$1实例,并且把地址返回给tiger//8. 匿名内部类使用一次就不能再使用了,但对象tiger可以反复调用。A tiger = new A() {@Overridepublic void cry() {System.out.println("老虎叫唤");}};//9. getClass()获取对象的运行类型System.out.println("tiger的运行类型:" + tiger.getClass() );tiger.cry();tiger.cry();tiger.cry();}
}
interface A {   //接口public void cry();
}

演示基于类匿名内部类的使用

//演示基于类的匿名内部类的使用
public class Inner02 {    //外部其他类public static void main(String[] args) {// TODO Auto-generated method stubOuter02 outer02 = new Outer02();outer02.method();}}
class Outer02 {   //外部类private int n1 = 10;public void method() {//基于类的匿名内部类的使用//1. father的编译类型Father//2. father的运行类型Outer02$2//3. 底层会创建匿名内部类 ,底层是继承关系,Outer02$2继承了father类//4. jack形参列表会自动传递给构造器Father father  = new Father("jack") {       //输出名字是jack			@Overridepublic void test() {// TODO Auto-generated method stubSystem.out.println("匿名内部类重写了test方法");}			};//getClass()获取对象的运行类型System.out.println("father对象的运行类型:" + father.getClass());  //输出Outer02$2father.test();        //输出匿名内部类重写了test方法//基于抽象类的匿名内部类的使用//抽象类中必须重写eat方法Animal animal = new Animal() {@Overridevoid eat() {// TODO Auto-generated method stubSystem.out.println("吃东西");}			};}
}
class Father {public Father(String name) {  //构造器System.out.println("名字是" + name);}public void test() {   //方法}
}
abstract class Animal {abstract void eat();
}==============================================
名字是jack
father对象的运行类型:class 类变量和类方法.Outer02$1
匿名内部类重写了test方法

使用细节

  1. 匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象。因此,从语法上看,它既有定义类的特征,也有创建对象的特征。
  2. 可以直接访问外部类的所有成员,包括私有的。
  3. 不能添加访问修饰符,因为它的低位就是一个局部变量。
  4. 匿名内部类的作用域仅仅是在它的方法或代码块中。
  5. 匿名内部类----访问------->外部类成员 【访问方式:直接访问】
  6. 外部其他类----不能访问------->匿名内部类(因为匿名内部类的地位就是一个局部变量)。
  7. 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则。
  8. 如果想访问外部类的成员,则可以使用外部类名.this.成员去访问。
public class Inner03 {public static void main(String[] args) {// TODO Auto-generated method stubOuter03 outer03 = new Outer03();outer03.f1();         //输出第一种调用方法匿名内部类重写了hi方法//如果匿名内部类中未重写hi方法,则输出  Person类中的hi方法}}
class Outer03 {    //外部类private int n1 = 99;//6. 外部其他类----不能访问------->匿名内部类//System.out.println(n2);public void f1() {//创建一个基于内部类的匿名//1. 第一种调用方法//3. 不能添加访问修饰符,因为它的低位就是一个局部变量。//Person person = new public Person()Person person = new Person() {private int n2 = 1000;@Overridepublic void hi() {//2. 可以直接访问外部类的所有成员,包括私有的。System.out.println(n1);System.out.println("第一种调用方法匿名内部类重写了hi方法");}			};//输出匿名内部类重写了hi方法person.hi();  //运行时存在动态绑定 ,运行类型是Outer03$3//2. 第二种调用方法//也可以直接调用,匿名内部类本身也是返回对象new Person() {private int n2 = 1000;@Overridepublic void hi() {// TODO Auto-generated method stubSystem.out.println("第二种调用方法匿名内部类重写了hi方法");}		}.hi();}
}
class Person {public void hi() {System.out.println("Person类中的hi方法");}
}
//抽象类、接口……都可以写

匿名内部类的最佳实践

练习一
public class Inner04 {public static void main(String[] args) {//匿名内部类可以当作实参去传递//f2()方法里传递的ILf2(new IL(){public void show() {System.out.println("这是一副名画");}});//传统方式//写一个类实现IL,将picture传给接口IL------硬编码f2(new Picture());}//静态方法,形参是接口类型public static void f2(IL il) {il.show();}}
interface IL {void show();
}
class Picture implements IL {@Overridepublic void show() {// TODO Auto-generated method stubSystem.out.println("这是一副名画");}}
练习二
  1. 有一个铃声接口Bell,里面有一个ring方法
  2. 有一个手机类cellphone,具有闹钟功能alarmblock,参数是Bell类型
  3. 测试手机的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
  4. 再传入另一个匿名内部类(对象),打印:小伙伴上课了
public class Inner05 {public static void main(String[] args) {// TODO Auto-generated method stubCellphone cellphone = new Cellphone();cellphone.alarmblock(new Bell() {@Overridepublic void ring() {// TODO Auto-generated method stubSystem.out.println("懒猪起床了");}			});cellphone.alarmblock(new Bell() {@Overridepublic void ring() {// TODO Auto-generated method stubSystem.out.println("小伙伴上课了");}			});}
}
interface Bell {void ring();
}
class Cellphone {public void alarmblock(Bell bell) {bell.ring();}
}

成员内部类

成员内部类是定义在外部类的成员位置,并且没有static修饰

  1. 可以直接访问外部类的所有成员,包含私有的。
  2. 可以添加任意访问符,因为它的地位是一个成员。
  3. 内部类编译后也会产生一个.class文件,其命名规则是:外部类名字$内部类名字.class
  4. 内部类可以使用所有访问限制修饰符,但外部类只能是public或缺省访问限制修饰符。
public class MemberInner01 {public static void main(String[] args) {// TODO Auto-generated method stubOuter01 outer01 = new Outer01();outer01.t1();}
}
class Outer01 {    //外部类private int n1 = 99;public String name = "张三"; class Inner01 {    //成员内部类public void say() {//可以直接访问外部类的所有成员,包含私有的。System.out.println("Outer01的n1=" + n1 + "Outer01的name=" + name);}}	public void t1() {Inner01 inner01 = new Inner01();inner01.say();}
}
  1. 作用域:和外部类成员一样,为整个类体。
  2. 成员内部类----->访问----->外部类成员(比如:属性)【访问方式:直接访问】。
  3. 外部类----->访问成员内部类【访问方式:创建对象再访问】。
  4. 外部其他类------>访问------->成员内部类【三种方法】
public class MemberInner01 {  //外部其他类public static void main(String[] args) {// TODO Auto-generated method stubOuter01 outer01 = new Outer01();outer01.t1();//外部其他类使用成员内部类的两种方式//第一种Outer01.Inner01 inner01 = outer01.new Inner01();inner01.say();//第二种;在外部类中编写一个方法可以返回Inner08对象Outer01.Inner01 inner01Instance = outer01.getInner01Instance();inner01Instance.say();		}
}
class Outer01 {    //外部类private int n1 = 99;public String name = "张三"; class Inner01 {    //成员内部类public void say() {//可以直接访问外部类的所有成员,包含私有的。System.out.println("Outer01的n1=" + n1 + "Outer01的name=" + name);}}	public void t1() {Inner01 inner01 = new Inner01();inner01.say();}//该方法返回Inner01的实例public Inner01 getInner01Instance() {return new Inner01();}
}
  1. 如果外部类和内部类重名时,内部类访问的话,默认就近原则,如果想访问外部类的成员时,可以使用外部类名.this.成员去访问。
class A02 {    //外部类private int n1 = 10;private static String name = "jack";//定义一个成员内部类class B02 {private int n1 = 20;//可以直接访问外部类的所有成员,包括私有的public void say() {System.out.println("B02 n1 = " + n1 + "A02 n1 = " + A02.this.n1);//B02 n1 = 20//A02 n1 = 10}}
}

静态内部类

是定义在外部类的成员位置,并且有static修饰。

  1. 可以直接访问外部类的所有静态成员,包括私有的,但不能访问非静态成员。
  2. 可以添加任何访问修饰符,因为它的地位就是一个成员。
  3. 作用域:同其他的成员,为整个类体。
  4. 静态内部类------->访问------->外部类(比如:静态属性)【访问方式:直接访问所有静态成员】。
  5. 外部类------->访问------->静态内部类【访问方式:创建对象再访问】。
  6. 外部其他类------->访问---------->静态内部类。
  7. 如果外部类和静态内部类重名时,静态内部类访问默认遵循就近原则,如果想访问外部类成员,则可以使用外部类名.成员去访问。
public class StaticInner01 {public static void main(String[] args) {    //外部其他类// TODO Auto-generated method stubOuter01 outer01 = new Outer01();outer01.hi();//外部其他类访问静态内部类//方式一://因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)。Outer01.Inner01 inner01 = new Outer01.Inner01();inner01.say();System.out.println("=====================");//方式二://编写一个方法可以返回静态内部类的实例outer01.getInner01();inner01.say();}}
class Outer01 {   //外部类private int n1 = 10;private static int n2 = 10;private static String name = "张三";//静态内部类public static class Inner01 {public void say() {//1.可以直接访问外部类的所有静态成员,包括私有的,但不能访问非静态成员。//System.out.println(n1);----->报错//2.静态内部类------->访问------->外部类(比如:静态属性)【访问方式:直接访问所有静态成员】。System.out.println(n2);}}//3. 作用域:同其他的成员,为整个类体。public void hi() {//4.外部类------->访问------->静态内部类【访问方式:创建对象再访问】。Inner01 inner01 = new Inner01();inner01.say();}public Inner01 getInner01() {   //静态方法、非静态方法的也可以return new Inner01();}
}

更多推荐

面向对象编程JAVA(高级部分)

本文发布于:2024-02-06 06:33:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1747224.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:面向对象   高级   JAVA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!