zoukankan      html  css  js  c++  java
  • Java学习路线:day15 面向对象(下)2

    全部源码:https://github.com/name365/JavaSE-30Day

    第四章 面向对象(下)

    抽象类与抽象方法

    随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类

    在这里插入图片描述

    /*
     * abstract 关键字的使用
     * 
     * 1.abstract:抽象的
     * 2.abstract 可以用来修饰的结构:类、方法
     * 3.abstract 修饰类:抽象类
     * 	》 此类不能实例化
     *  》 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化全过程)
     *  》 开发中,都会提供抽象类的子类,让子类对象实例化,实现相关的操作
     * 
     * 4.abstract 修饰方法:抽象方法
     *  > 抽象方法,只有方法的声明,没有方法体。
     *  > 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法
     *  > 若子类重写了父类中所有的抽象方法,此子类,
     *
     * abstract 使用上的注意点:
     * 1.abstract 不能用来修饰变量、代码块、构造器;
     * 
     * 2.abstract 不能用来修饰私有方法、静态方法、final 的方法、final 的类。
     * 
     */
    public class AbstractTest {
    	public static void main(String[] args) {
    		//一旦 Person 类抽象了,就不可实例化
    //		Person p1 = new Person();
    //		p1.eat();
    		
    	}
    }
    
    abstract class Creature{
    	public abstract void breath();
    }
    
    abstract class Person extends Creature{
    	String name;
    	int age;
    	
    	public Person(){
    		
    	}
    	
    	public Person(String name,int age){
    		this.name = name;
    		this.age = age;
    	}
    	
    	//不是抽象方法
    //	public void eat(){
    //		System.out.println("人吃饭");
    //	}
    	
    	//抽象方法
    	public abstract void eat();
    	
    	public void walk(){
    		System.out.println("人走路");
    	}
    }
    
    class Student extends Person{
    	public Student(String name,int age){
    		super(name,age);
    	}
    	public void eat(){
    		System.out.println("学生应该多吃有营养的。");
    	}
    	@Override
    	public void breath() {
    		System.out.println("学生应该呼吸新鲜的无雾霾空气");
    	}
    }
    

    抽象类应用

    抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。

    在这里插入图片描述

    问题:卡车(Truck)和驳船(RiverBarge)的燃料效率和行驶距离的计算方法完全不同。Vehicle 类不能提供计算方法,但子类可以。

    /* Java 允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提  供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。
     * Vehicle 是一个抽象类,有两个抽象方法。
     * 注意:抽象类不能实例化 new Vihicle()是非法的
     */
    public abstract class Vehicle{
    	public abstract double calcFuelEfficiency();//计算燃料效率的抽象方法
    	public abstract double calcTripDistance();//计算行驶距离的抽象方法
    }
    public class Truck extends Vehicle{
    	public double calcFuelEfficiency(){ 
    		//写出计算卡车的燃料效率的具体方法
    	}
    	public double calcTripDistance(){ 
    		//写出计算卡车行驶距离的具体方法
    	}
    }
    public class RiverBarge extends Vehicle{
    	public double calcFuelEfficiency() { 
    		//写出计算驳船的燃料效率的具体方法
    	}
    	public double calcTripDistance( )  {  
    		//写出计算驳船行驶距离的具体方法
    	}
    }
    

    练习

    /*
     * 编写一个 Employee 类,声明为抽象类,
     * 包含如下三个属性:name,id,salary。
     * 提供必要的构造器和抽象方法:work()。
     * 对于 Manager 类来说,他既是员工,还具有奖金(bonus)的属性。
     * 请使用继承的思想,设计 CommonEmployee 类和 Manager 类,
     * 要求类中提供必要的方法进行属性访问。
     * 
     */
    public abstract class Employee {
    	
    	private String name;
    	private int id;
    	private double salary;
    	
    	public Employee(){
    		super();
    	}
    
    	public Employee(String name, int id, double salary) {
    		super();
    		this.name = name;
    		this.id = id;
    		this.salary = salary;
    	}
    	
    	public abstract void work();	
    }
    
    • Manager 类
    /*
     * 对于 Manager 类来说,他既是员工,还具有奖金(bonus)的属性。
     * 
     */
    public class Manager extends Employee{
    
    	private double bonus;	//奖金
    	
    	public Manager(double bonus) {
    		super();
    		this.bonus = bonus;
    	}
    	
    	public Manager(String name, int id, double salary, double bonus) {
    		super(name, id, salary);
    		this.bonus = bonus;
    	}
    
    
    	@Override
    	public void work() {
    		System.out.println("管理员工,提高公司运行效率。");		
    	}
    }
    
    • CommonEmployee 类
    public class CommonEmployee extends Employee {
    
    	@Override
    	public void work() {
    		System.out.println("员工在一线车间生产产品。");
    	}
    
    }
    
    • 测试类
    /*
     * 请使用继承的思想,设计 CommonEmployee 类和 Manager 类,
     */
    public class EmployeeTest {
    	public static void main(String[] args) {
    		
    		Employee manager = new Manager("库克",1001,5000,50000);
    		
    		manager.work();
    		
    		CommonEmployee commonEmployee = new CommonEmployee();
    		commonEmployee.work();
    	}
    }
    

    创建抽象类的匿名子类对象

    public class Num {
    
    }
    
    abstract class Creature{
    	public abstract void breath();
    }
    
    abstract class Person extends Creature{
    	String name;
    	int age;
    	
    	public Person(){
    		
    	}
    	
    	public Person(String name,int age){
    		this.name = name;
    		this.age = age;
    	}
    	
    	//不是抽象方法
    //	public void eat(){
    //		System.out.println("人吃饭");
    //	}
    	
    	//抽象方法
    	public abstract void eat();
    	
    	public void walk(){
    		System.out.println("人走路");
    	}
    }
    
    class Student extends Person{
    	public Student(String name,int age){
    		super(name,age);
    	}
    	public Student(){
    
    	}
    	public void eat(){
    		System.out.println("学生应该多吃有营养的。");
    	}
    	@Override
    	public void breath() {
    		System.out.println("学生应该呼吸新鲜的无雾霾空气");
    	}
    }
    
    • PersonTest 类
    /*
     * 抽象类的匿名子类
     * 
     */
    public class PersonTest {
    	public static void main(String[] args) {
    		
    		method(new Student());	//匿名对象
    		
    		Worker worker = new Worker(); 
    		method1(worker);	//非匿名的类非匿名的对象
    		
    		method1(new Worker());	//非匿名的类匿名的对象
    		
    		System.out.println("*********************");
    		
    		//创建了一个匿名子类的对象:p
    		Person p = new Person(){
    
    			@Override
    			public void eat() {
    				System.out.println("吃东西");
    			}
    
    			@Override
    			public void breath() {
    				System.out.println("呼吸空气");
    			}
    			
    		};
    		method1(p);
    		System.out.println("**********************"); 
    		//创建匿名子类的匿名对象
    		method1(new Person(){
    
    			@Override
    			public void eat() {
    				System.out.println("吃零食");
    			}
    
    			@Override
    			public void breath() {
    				System.out.println("云南的空气");
    			}
    			
    		});
    	}
    	
    	public static void method1(Person p){
    		p.eat();
    		p.walk();
    	}
    	
    	public static void method(Student s){
    		
    	}
    }
    class Worker extends Person{
    	
    	@Override
    	public void eat() {
    	}
    
    	@Override
    	public void breath() {
    	}
    }
    

    多态的应用:模板方法设计模式(TemplateMethod)

    抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
    解决的问题:
    》当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
    》换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式

    • 例 1
    /*
     * 抽象类的应用:模板方法的设计模式
     */
    public class TemplateTest {
    	public static void main(String[] args) {
    		
    		SubTemlate t = new SubTemlate();
    		
    		t.sendTime();
    	}
    }
    abstract class Template{
    	
    	//计算某段代码执行所需花费的时间
    	public void sendTime(){
    		
    		long start = System.currentTimeMillis();
    		
    		code();	//不确定部分,易变的部分
    		
    		long end = System.currentTimeMillis();
    		
    		System.out.println("花费的时间为:" + (end - start));
    	}
    	
    	public abstract void code();
    }
    
    class SubTemlate extends Template{
    	
    	@Override
    	public void code() {
    		
    		for(int i = 2;i <= 1000;i++){
    			boolean isFlag = true;
    			for(int j = 2;j <= Math.sqrt(i);j++){
    				if(i % j == 0){
    					isFlag = false;
    					break;
    				}
    			}
    			if(isFlag){
    				System.out.println(i);
    			}
    		}
    	}
    }
    
    • 例 2
    //抽象类的应用:模板方法的设计模式
    public class TemplateMethodTest {
    
    	public static void main(String[] args) {
    		BankTemplateMethod btm = new DrawMoney();
    		btm.process();
    
    		BankTemplateMethod btm2 = new ManageMoney();
    		btm2.process();
    	}
    }
    abstract class BankTemplateMethod {
    	// 具体方法
    	public void takeNumber() {
    		System.out.println("取号排队");
    	}
    
    	public abstract void transact(); // 办理具体的业务 //钩子方法
    
    	public void evaluate() {
    		System.out.println("反馈评分");
    	}
    
    	// 模板方法,把基本操作组合到一起,子类一般不能重写
    	public final void process() {
    		this.takeNumber();
    
    		this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码
    
    		this.evaluate();
    	}
    }
    
    class DrawMoney extends BankTemplateMethod {
    	public void transact() {
    		System.out.println("我要取款!!!");
    	}
    }
    
    class ManageMoney extends BankTemplateMethod {
    	public void transact() {
    		System.out.println("我要理财!我这里有 2000 万美元!!");
    	}
    }
    
    • 模板方法设计模式是编程中经常用得到的模式。各个框架、类库中都有他的影子,比如常见的有:
      • 数据库访问的封装
      • Junit 单元测试
      • JavaWeb 的 Servlet 中关于 doGet/doPost 方法调用
      • Hibernate 中模板程序
      • Spring 中 JDBCTemlate、HibernateTemplate 等

    抽象类的练习

    在这里插入图片描述
    在这里插入图片描述

    • Employee 类
    /*
     * 定义一个 Employee 类,
     * 该类包含:private 成员变量 name,number,birthday,
     * 其中 birthday 为 MyDate 类的对象;
     * abstract 方法 earnings();
     * toString()方法输出对象的 name,number 和 birthday。
     * 
     */
    public abstract class Employee {
    	private String name;
    	private int number;
    	private MyDate birthday;
    	
    	public Employee(String name, int number, MyDate birthday) {
    		super();
    		this.name = name;
    		this.number = number;
    		this.birthday = birthday;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getNumber() {
    		return number;
    	}
    
    	public void setNumber(int number) {
    		this.number = number;
    	}
    
    	public MyDate getBirthday() {
    		return birthday;
    	}
    
    	public void setBirthday(MyDate birthday) {
    		this.birthday = birthday;
    	}
    
    	public abstract double earnings();
    
    	@Override
    	public String toString() {
    		return "name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString() + "]";
    	}
    	
    }
    
    • MyDate 类
    /*
     * MyDate 类包含:private 成员变量 year,month,day;
     * toDateString()方法返回日期对应的字符串:xxxx 年 xx 月 xx 日
     */
    public class MyDate {
    	private int year;
    	private int month;
    	private int day;
    	
    	public MyDate(int year, int month, int day) {
    		super();
    		this.year = year;
    		this.month = month;
    		this.day = day;
    	}
    
    	public int getYear() {
    		return year;
    	}
    
    	public void setYear(int year) {
    		this.year = year;
    	}
    
    	public int getMonth() {
    		return month;
    	}
    
    	public void setMonth(int month) {
    		this.month = month;
    	}
    
    	public int getDay() {
    		return day;
    	}
    
    	public void setDay(int day) {
    		this.day = day;
    	}
    
    	public String toDateString(){
    		return year + "年" + month + "月" + day + "日";
    	}
    }
    
    • SalariedEmployee 类
    /*
     * 定义 SalariedEmployee 类继承 Employee 类,实现按月计算工资的员工处理。
     * 该类包括:private 成员变量 monthlySalary;实现父类的抽象方法 earnings(),
     * 该方法返回 monthlySalary 值;
     * toString()方法输出员工类型信息及员工的 name,number,birthday。
     * 
     */
    public class SalariedEmployee extends Employee{
    	private double monthlySalary;	//月工资
    
    	public SalariedEmployee(String name,int number,MyDate birthday) {
    		super(name,number,birthday);
    	}
    	
    	public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) {
    		super(name, number, birthday);
    		this.monthlySalary = monthlySalary;
    	}
    
    	@Override
    	public double earnings() {
    		return monthlySalary;		
    	}
    
    	@Override
    	public String toString() {
    		return "SalariedEmployee [" + super.toString() + "]";
    	}	
    }
    
    • HourlyEmployee 类
    /*
     * 参照 SalariedEmployee 类定义 HourlyEmployee 类,
     * 实现按小时计算工资的员工处理。该类包括:private 成员变量 wage 和 hour;
     * 实现父类的抽象方法 earnings(),该方法返回 wage*hour 值;
     * toString()方法输出员工类型信息及员工的 name,number,birthday。
     * 
     */
    public class HourlyEmployee extends Employee{
    	private int wage;	//每小时的工资
    	private int hour;	//月工作的小时数
    	
    	public HourlyEmployee(String name, int number, MyDate birthday) {
    		super(name, number, birthday);
    	}
    
    	public HourlyEmployee(String name, int number, MyDate birthday, int wage, int hour) {
    		super(name, number, birthday);
    		this.wage = wage;
    		this.hour = hour;
    	}
    
    	@Override
    	public double earnings() {
    		return wage*hour;
    	}
    
    	public int getWage() {
    		return wage;
    	}
    
    	public void setWage(int wage) {
    		this.wage = wage;
    	}
    
    	public int getHour() {
    		return hour;
    	}
    
    	public void setHour(int hour) {
    		this.hour = hour;
    	}
    	
    	public String toString(){
    		return "HourlyEmployee[" + super.toString() + "]"; 
    	}
    }
    
    • PayrollSystem 类
    import java.util.Calendar;
    import java.util.Scanner;
    /*
     * 定义 PayrollSystem 类,创建 Employee 变量数组并初始化,
     * 该数组存放各类雇员对象的引用。利用循环结构遍历数组元素,
     * 输出各个对象的类型,name,number,birthday,以及该对象生日。
     * 当键盘输入本月月份值时,
     * 如果本月是某个 Employee 对象的生日,还要输出增加工资信息。
     * 
     */
    public class PayrollSystem {
    	public static void main(String[] args) {
    		//方式一:
    //		Scanner scanner = new Scanner(System.in);
    //		System.out.println("请输入当月的月份:");
    //		int month = scanner.nextInt();
    		
    		//方式二:
    		Calendar calendar = Calendar.getInstance();
    		int month = calendar.get(Calendar.MONTH);//获取当前的月份
    //		System.out.println(month);//一月份:0
    		
    		Employee[] emps = new Employee[2];
    		
    		emps[0] = new SalariedEmployee("马良", 1002,new MyDate(1992, 2, 28),10000);
    		emps[1] = new HourlyEmployee("博西", 2001, new MyDate(1991, 1, 6),60,240);
    		
    		for(int i = 0;i < emps.length;i++){
    			System.out.println(emps[i]);
    			double salary = emps[i].earnings();
    			System.out.println("月工资为:" + salary);
    			
    			if((month+1) == emps[i].getBirthday().getMonth()){
    				System.out.println("生日快乐!奖励 100 元");
    			}
    			
    		}
    	}
    }
    

    接口(interface)

    概述

    • 一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java 不支持多重继承。有了接口,就可以得到多重继承的效果。
    • 另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有 is-a 的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3 机、手机、数码相机、移动硬盘等都支持 USB 连接。
    • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系
    • 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
      在这里插入图片描述
    /* 接口(interface)是抽象方法和常量值定义的集合。
     * 接口的特点:
     * 用 interface 来定义。
     * 接口中的所有成员变量都默认是由 publicstaticfinal 修饰的。
     * 接口中的所有抽象方法都默认是由 publicabstract 修饰的。
     * 接口中没有构造器。
     * 接口采用多继承机制。
     */
    

    在这里插入图片描述

    /*
     * 接口的使用
     * 1.接口使用 interface 来定义。
     * 2.在 Java 中:接口和类是并列的两个结构
     * 3.如何去定义两个接口:定义接口中的成员
     * 	》3.1 JDK7 及以前:只能定义全局常量和抽象方法
     * 		》全局常量:public static final 的,但是书写中,可以省略不写。
     * 		》抽象方法:public abstract 的
     * 
     *  》3.2 JDK8:除了全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)。
     * 
     * 4.接口中不能定义构造器!意味着接口不可以实例化。
     * 
     * 5.Java 开发中,接口通过让类去实现(implements)的方式来使用。
     *   如果实现类覆盖了接口中的所有方法,则此实现类就可以实例化
     *   如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
     * 
     * 6.Java 类可以实现多个接口 ---》弥补了 Java 单继承性的局限性
     *  格式:class AA extends BB implementd CC,DD,EE
     *  
     *  7.接口与接口之间是继承,而且可以多继承
     *  
     **********************************
     * 8.接口的具体使用,体现多态性
     * 	   接口的主要用途就是被实现类实现。(面向接口编程)
     * 9.接口,实际可以看作是一种规范
     * 
     * 面试题:抽象类与接口有哪些异同?
     *  
     */
    public class InterfaceTest {
    	public static void main(String[] args) {
    		System.out.println(Flayable.MAX_SPEED);
    		System.out.println(Flayable.MIN_SPEED);
    	}
    }
    interface Flayable{
    	
    	//全局变量
    	public static final int MAX_SPEED = 7900;	
    	int MIN_SPEED = 1;//省略了 public static final 
    	
    	//抽象方法
    	public abstract void fly();
    	
    	void stop();//省略了 public abstract 
    	//Interfaces cannot have constructors
    //	public Flayable(){
    //		
    //	}	
    }
    interface Attackable{
    	void attack();
    }
    
    class Plane implements Flayable{
    
    	@Override
    	public void fly() {
    		System.out.println("飞机通过引擎起飞");
    		
    	}
    
    	@Override
    	public void stop() {
    		System.out.println("驾驶员减速停止");
    	}
    	
    }
    abstract class Kite implements Flayable{
    
    	@Override
    	public void fly() {
    		
    	}
    }
    
    class Bullet extends Object implements Flayable,Attackable,CC{
    
    	@Override
    	public void attack() {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void fly() {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void stop() {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void method1() {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void method2() {
    		// TODO Auto-generated method stub
    		
    	}
    }
    
    //*********************************
    interface AA{
    	void method1();
    }
    interface BB{
    	void method2();
    }
    interface CC extends AA,BB{
    	
    }
    

    在这里插入图片描述
    在这里插入图片描述

    举例

    /*
     * 接口的使用
     * 1.接口使用上也满足多态性
     * 2.接口,实际上就是定义了一种规范
     * 3.开发中,体会面向接口编程!
     * 
     */
    public class USBTest {
    	public static void main(String[] args) {
    		
    		Computer com = new Computer();
    		//1.创建了接口的非匿名实现类的非匿名对象
    		Flash flash = new Flash();
    		com.transferData(flash); 
    		//2. 创建了接口的非匿名实现类的匿名对象
    		com.transferData(new Printer());
    		//3. 创建了接口的匿名实现类的非匿名对象
    		USB phone = new USB(){
    
    			@Override
    			public void start() {
    				System.out.println("手机开始工作");
    			}
    
    			@Override
    			public void stop() {
    				System.out.println("手机结束工作");
    			}
    			
    		};
    		com.transferData(phone);
    		//4. 创建了接口的匿名实现类的匿名对象
    		com.transferData(new USB(){
    			@Override
    			public void start() {
    				System.out.println("mp3 开始工作");
    			}
    
    			@Override
    			public void stop() {
    				System.out.println("mp3 结束工作");
    			}
    		});
    	}
    }
    
    class Computer{
    	
    	public void transferData(USB usb){//USB usb = new Flash();
    		usb.start();
    		
    		System.out.println("具体传输数据的细节");
    		
    		usb.stop();
    	}
    	
    }
    
    interface USB{
    	//常量:定义了长、宽
    	void start();
    	
    	void stop();
    }
    class Flash implements USB{
    
    	@Override
    	public void start() {
    		System.out.println("U 盘开始工作");
    	}
    
    	@Override
    	public void stop() {
    		System.out.println("U 盘结束工作");
    	}
    }
    class Printer implements USB{
    	@Override
    	public void start() {
    		System.out.println("打印机开启工作");
    	}
    
    	@Override
    	public void stop() {
    		System.out.println("打印机结束工作");
    	}
    	
    }
    

    接口的应用:代理模式(Proxy)

    概述:代理模式是 Java 开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。

    在这里插入图片描述

    /*
     * 接口的应用:代理模式
     * 
     * 
     */
    public class NetWorkTest {
    	public static void main(String[] args) {
    		
    		Server server = new Server();
    //		server.browse();
    		ProxyServer proxyServer = new ProxyServer(server);
    		
    		proxyServer.browse();
    	}
    }
    interface NetWork{
    	public void browse();
    	
    }
    //被代理类
    class Server implements NetWork{
    
    
    	@Override
    	public void browse() {
    		System.out.println("真实的服务器来访问网络");
    	}
    }
    //代理类
    class ProxyServer implements NetWork{
    	
    	private NetWork work;
    	
    	public ProxyServer(NetWork work){
    		this.work = work;
    	}
    	
    	public void check(){
    		System.out.println("联网前的检查工作");
    	}
    
    	@Override
    	public void browse() {
    		check();
    		
    		work.browse();
    	}
    	
    }
    
    • 应用场景:
      • 安全代理:屏蔽对真实角色的直接访问。
      • 远程代理:通过代理类处理远程方法调用(RMI)
      • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象

    比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有 100MB,在打开文件时,不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用 proxy 来进行大图片的打开。

    • 分类
      • 静态代理(静态定义代理类)
      • 动态代理(动态生成代理类)
        • JDK 自带的动态代理,需要反射等知识
    public class StaticProxyTest {
    
    	public static void main(String[] args) {
    		Proxy s = new Proxy(new RealStar());
    		s.confer();
    		s.signContract();
    		s.bookTicket();
    		s.sing();
    		s.collectMoney();
    	}
    }
    
    interface Star {
    	void confer();// 面谈
    
    	void signContract();// 签合同
    
    	void bookTicket();// 订票
    
    	void sing();// 唱歌
    
    	void collectMoney();// 收钱
    }
    //被代理类
    class RealStar implements Star {
    
    	public void confer() {
    	}
    
    	public void signContract() {
    	}
    
    	public void bookTicket() {
    	}
    
    	public void sing() {
    		System.out.println("明星:歌唱~~~");
    	}
    
    	public void collectMoney() {
    	}
    }
    
    //代理类
    class Proxy implements Star {
    	private Star real;
    
    	public Proxy(Star real) {
    		this.real = real;
    	}
    
    	public void confer() {
    		System.out.println("经纪人面谈");
    	}
    
    	public void signContract() {
    		System.out.println("经纪人签合同");
    	}
    
    	public void bookTicket() {
    		System.out.println("经纪人订票");
    	}
    
    	public void sing() {
    		real.sing();
    	}
    
    	public void collectMoney() {
    		System.out.println("经纪人收钱");
    	}
    }
    

    接口的应用:工厂模式

    拓展:工厂设计模式.pdf

    • 接口和抽象类之间的对比
    No. 区别点 抽象类 接口
    1 定义 包含抽象方法的类 主要是抽象方法和全局常量的集合
    2 组成 构造方法、抽象方法、普通方法、常量、变量 常量、抽象方法、(jdk8.0:默认方法、静态方法)
    3 使用 子类继承抽象类(extends) 子类实现接口(implements)
    4 关系 抽象类可以实现多个接口 接口不能继承抽象类,但允许继承多个接口
    5 常见设计模式 模板方法 简单工厂、工厂方法、代理模式
    6 对象 都通过对象的多态性产生实例化对象
    7 局限 抽象类有单继承的局限 接口没有此局限
    8 实际 作为一个模板 是作为一个标准或是表示一种能力
    9 选择 如果抽象类和接口都可以使用的话,优先使用接口,因为避免单继承的局限

    在开发中,常看到一个类不是去继承一个已经实现好的类,而是要么继承抽象类,要么实现接口。
    -【面试题】排错:

    interface A {
    	int x = 0;
    }
    class B {
    	int x = 1;
    }
    class C extends B implements A {
    	public void pX() {
    //		编译不通过,x 不明确
    		System.out.println(x);
    //		System.out.println(super.x); //1
    //		System.out.println(A.x);//0
    	}
    	public static void main(String[] args) {
    		new C().pX();
    	}
    }
    
    • 排错 2:
    interface Playable {
    	void play();
    }
    interface Bounceable {
    	void play();
    }
    interface Rollable extends Playable, Bounceable {
    	Ball ball= new Ball("PingPang"); //省略了 public static final
    }
    public class Ball implements Rollable {
    	private String name;
    	public String getName() {
    		return name;
    	}
    	public Ball(String name) {
    		this.name= name;
    	}
    	public void play() {
    		ball = new Ball("Football"); //The final field Rollable.ball cannot be assigned	
    		System.out.println(ball.getName());
    	}
    }
    
    • 练习
      在这里插入图片描述

    • CompareObject 类

    /*
     * 定义一个接口用来实现两个对象的比较。
     * 
     */
    public interface CompareObject {
    	public int compareTo(Object o);
    	//若返回值是 0,代表相等;若为正数,代表当前对象大;负数代表当前对象小
    	
    }
    
    • Circle 类
    /*
     * 定义一个 Circle 类,声明 redius 属性,提供 getter 和 setter 方法
     */
    public class Circle {
    	
    	private Double radius;
    
    	public Double getRadius() {
    		return radius;
    	}
    
    	public void setRadius(Double radius) {
    		this.radius = radius;
    	}
    
    	public Circle() {
    		super();
    	}
    
    	public Circle(Double radius) {
    		super();
    		this.radius = radius;
    	}
    		
    }
    
    • ComparableCircle 类
    /*
     * 定义一个 ComparableCircle 类,继承 Circle 类并且实现 CompareObject 接口。在 ComparableCircle 类中给出接口中方法 compareTo 的实现体,
     * 用来比较两个圆的半径大小。
     */
    public class ComparableCircle extends Circle implements CompareObject{
    
    	public ComparableCircle(double radius) {
    		super(radius);
    	}
    	@Override
    	public int compareTo(Object o) {
    		if(this == o){
    			return 0;
    		}
    		if(o instanceof ComparableCircle){
    			ComparableCircle c = (ComparableCircle)o;
    			//错误的写法
    //			return (int)(this.getRedius() - c.getRedius());
    			//正确的方式一:
    //			if(this.getRadius() > c.getRadius()){
    //				return 1;
    //			}else if(this.getRadius() < c.getRadius()){
    //				return -1;
    //			}else{
    //				return 0;
    //			}
    			//当属性 radius 声明为 Double 类型时,可以调用包装类的方法
    			//正确的方式二:
    			return this.getRadius().compareTo(c.getRadius());
    		}else{
    			return 0;
    //			throw new RuntimeException("传入数据类型不匹配");
    		}
    	}
    }
    
    • InterfaceTest 类
    /*
     * 定义一个测试类 InterfaceTest,创建两个 ComparableCircle 对象,
     * 调用 compareTo 方法比较两个类的半径大小。
     * 
     */
    public class InterfaceTest {
    	public static void main(String[] args) {
    		
    		ComparableCircle c1 = new ComparableCircle(3.4);
    		ComparableCircle c2 = new ComparableCircle(3.6);
    		
    		int compareValue = c1.compareTo(c2);
    		if(compareValue > 0){
    			System.out.println("c1 对象大");
    		}else if(compareValue < 0){
    			System.out.println("c2 对象大");
    		}else{
    			System.out.println("两个一样的");
    		}
    		
    		int compareValue1 = c1.compareTo(new String("AA"));
    		System.out.println(compareValue1);
    	}
    }
    

    Java 8 中关于接口的改进

    Java 8 中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。

    静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像 Collection/Collections 或者 Path/Paths 这样成对的接口和类。

    默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如:java 8 API 中对 Collection、List、Comparator 等接口提供了丰富的默认方法。

    • 例1
    • interface 类
    /*
     * JDK8:除了全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)。
     * 
     * 
     */
    public interface CompareA {
    
    	//静态方法
    	public static void method1() {
    		System.out.println("CompareA:西安");
    	}
    	
    	//默认方法
    	public default void method2(){
    		System.out.println("CompareA:深圳");
    	}
    	
    	default void method3(){
    		System.out.println("CompareA:杭州");
    	}
    }
    
    • SubClassTest 类
    public class SubClassTest {
    
    	public static void main(String[] args) {
    		SubClass s = new SubClass();
    //		s.method1();
    //		SubClass.method1();
    //		知识点 1:接口中定义的静态方法,只能通过接口来调用。
    		CompareA.method1();
    //		知识点 2:通过实现类的对象,可以调用接口中的默认方法。
    //		如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
    		s.method2();
    //		知识点 3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
    //		那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则
    //		知识点 4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
    //		那么在实现类没有重写此方法的情况下,报错。-->接口冲突。
    //		这就需要我们必须在实现类中重写此方法
    		s.method3();
    		
    	}
    }
    class SubClass extends SuperClass implements CompareA,CompareB{
    	
    	public void method2(){
    		System.out.println("SubClass:上海");
    	}
    	
    	public void method3(){
    		System.out.println("SubClass:深圳");
    	}
    	
    //	知识点 5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
    	public void myMethod(){
    		method3(); //调用自己定义的重写的方法
    		super.method3(); //调用的是父类中声明的
    //		调用接口中的默认方法
    		CompareA.super.method3();
    		CompareB.super.method3();
    	}
    }
    
    • SuperClass 类
    public class SuperClass {
    	public void method3(){
    		System.out.println("SuperClass:北京");
    	}
    }
    
    • CompareB 类
    public interface CompareB {
    	default void method3(){
    		System.out.println("CompareB:上海");
    	}
    }
    
    • 例2
    /*
     * 练习:接口冲突的解决方式
     */
    interface Filial {// 孝顺的
    	default void help() {
    		System.out.println("老妈,我来救你了");
    	}
    }
    
    interface Spoony {// 痴情的
    	default void help() {
    		System.out.println("媳妇,别怕,我来了");
    	}
    }
    
    class Father{
    	public void help(){
    		System.out.println("儿子,救我媳妇!");
    	}
    }
    
    class Man extends Father implements Filial, Spoony {
    
    	@Override
    	public void help() {
    		System.out.println("我该就谁呢?");
    		Filial.super.help();
    		Spoony.super.help();
    	}
    	
    }
    

    类的内部成员之五:内部类

    当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。

    /*
     * 类的内部成员之五:内部类
     * 
     * 1.Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B就是外部类.
     * 
     * 2.内部类的分类:成员内部类	VS	局部内部类(方法内、代码块内、构造器内)
     * 		
     * 3.成员内部类
     * 	》作为外部类的成员,
     * 		- 调用外部类的结构
     * 		- 可以被static修饰
     * 		- 可以被4种不同的权限修饰
     * 
     *  》作为一个类,
     *  	- 类内可以定义属性、方法、构造器等
     *  	- 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
     *  	- 可以abstract修饰
     * 
     * 4.关注如下的3个问题
     *   》 如何实例化成员内部类的对象
     *   》 如何在成员内部类中区分调用外部类的结构
     *   》 开发中局部内部类的使用  见《InnerClassTest1.java》
     */
    public class InnerClassTest {
    	public static void main(String[] args) {
    		
    		//创建Dog实例(静态的成员内部类)
    		Person.Dog dog = new Person.Dog();
    		dog.show();
    		
    		//创建Bird实例(非静态的成员内部类)
    //		Person.Bird bird = new Person.Bird();
    		Person p = new Person();
    		Person.Bird bird = p.new Bird();
    		bird.sing();
    		
    		System.out.println();
    		
    		bird.display("喜鹊");
    	}
    }
    class Person{
    	String name = "李雷";
    	int age;
    	
    	public void eat(){
    		System.out.println("人,吃饭");
    	}
    	
    	//静态成员内部类
    	static class Dog{
    		String name;
    		int age;
    		
    		public void show(){
    			System.out.println("卡拉是条狗");
    //			eat();
    		}
    	}
    	
    	//非静态成员内部类
    	class Bird{
    		String name = "杜鹃";
    		public Bird(){
    			
    		}
    		
    		public void sing(){
    			System.out.println("我是一只猫头鹰");
    			Person.this.eat();//调用外部类的非静态属性
    			eat();
    			System.out.println(age);
    		}
    		
    		public void display(String name){
    			System.out.println(name);	//方法的形参
    			System.out.println(this.name);	//内部类的属性
    			System.out.println(Person.this.name);	//外部类的属性
    		}
    	}
    	public void method(){
    		//局部内部类
    		class AA{
    			
    		}
    	}
    	
    	{
    		//局部内部类
    		class BB{
    			
    		}
    	}
    	
    	public Person(){
    		//局部内部类
    		class CC{
    			
    		}
    	}
    }
    
    • InnerClassTest1类
    public class InnerClassTest1 {
    	
    //	开发中很少见
    	public void method(){
    //		局部内部类
    		class AA{
    			
    		}
    	}
    	
    //	返回一个实现了Comparable接口的类的对象
    	public Comparable getComparable(){
    		
    //		创建一个实现了Comparable接口的类:局部内部类
    		//方式一:
    //		class MyComparable implements Comparable{
    //
    //			@Override
    //			public int compareTo(Object o) {
    //				return 0;
    //			}
    //			
    //		}
    //		
    //		return new MyComparable();
    		
    		//方式二:
    		return new Comparable(){
    
    
    			@Override
    			public int compareTo(Object o) {
    				return 0;
    			}
    			
    		};
    		
    	}
    }
    

    匿名内部类

    /*
     * 1.匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。
     * 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
     * 
     * 2.格式:
     * 		new 父类构造器(实参列表)|实现接口(){
     * 				//匿名内部类的类体部分
     * 		}
     * 
     * 3.匿名内部类的特点
     * 		> 匿名内部类必须继承父类或实现接口
     * 		> 匿名内部类只能有一个对象
     * 		> 匿名内部类对象只能使用多态形式引用
     */
    interface Product{
    	public double getPrice();
    	public String getName();
    }
    public class AnonymousTest{
    	public void test(Product p){
    		System.out.println("购买了一个" + p.getName() + ",花掉了" + p.getPrice());
    	}
    	public static void main(String[] args) {
    		AnonymousTest ta = new AnonymousTest();
    		//调用test方法时,需要传入一个Product参数,
    		//此处传入其匿名实现类的实例
    		ta.test(new Product(){
    			public double getPrice(){
    				return 567.8;
    			}
    			public String getName(){
    				return "AGP显卡";
    			}
    		});
    	}
    }
    

    局部内部类的使用注意

    public class InnerClassTest {
    	
    //	public void onCreate(){
    //	
    //	int number = 10;
    //	
    //	View.OnClickListern listener = new View.OnClickListener(){
    //		
    //		public void onClick(){
    //			System.out.println("hello!");
    //			System.out.println(number);
    //		}
    //		
    //	}
    //	
    //	button.setOnClickListener(listener);
    //	
    //}
    
    	/*
    	 * 在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,
    	 * 要求此局部变量声明为final的。
    	 * 
    	 * jdk 7及之前版本:要求此局部变量显式的声明为final的
    	 * jdk 8及之后的版本:可以省略final的声明
    	 * 
    	 */
    	public void method(){
    		//局部变量
    		int num = 10;
    		
    		class AA{
    			
    			public void show(){
    //				num = 20;	//Local variable num defined in an enclosing scope must be final or effectively final
    				System.out.println(num);
    			}
    		}
    	}
    }
    

    面向对象思维导图总结

    • 导图1
      在这里插入图片描述

    • 导图2
      在这里插入图片描述

    整个Java全栈系列都是笔者自己敲的笔记。写作不易,如果可以,点个赞呗!✌

    欢迎查阅
  • 相关阅读:
    分布式文件存储系统-HDFS
    Java中的常用类
    分布式协调框架ZooKeeper
    【Redis】Redis慢查询
    kubectl工具管理应用
    kubectl命令管理
    To check your hdfs port use the following command in linux
    hadoop HDFS常用文件操作命令
    在scala中关于split以及正则表达式
    pandas入门之Series
  • 原文地址:https://www.cnblogs.com/gh110/p/12904628.html
Copyright © 2011-2022 走看看