zoukankan      html  css  js  c++  java
  • Java抽象类、接口和内部类

    1.抽象方法、抽象类

    1)抽象方法:

    • 由abstract修饰
    • 只有方法的定义,没有方法的具体实现(连{}都没有)

      由abstract修饰的方法为抽象方法,抽象方法只有方法的定义,没有方法体实现,用一个分号结尾。即:方法五要素中,抽象方法缺少了一个要素(方法体),也可以将抽象方法理解为不完整的方法。

     

    2)抽象类:

    • 由abstract修饰
    • 包含抽象方法的类必须是抽象类,不包含抽象方法的类也可以声明抽象类(意义不大)
    • 抽象类不能被实例化
    • 抽象类是需要被继承的
        • 子类需要重写抽象类的所有抽象方法---常用
        • 子类也可以声明为抽象类---不常用
    • 抽象类的意义:
        • 封装子类所共有的属性和行为---代码复用
        • 为所有子类提供一种统一的类型---向上造型
        • 可以包含抽象方法,为所有子类提供了统一的入口,子类的实现不同,但入口是一致的

      由abstract修饰的类为抽象类,抽象类是不能实例化对象的,而一个类不能实例化是没有意义的,所以需要定义类来继承抽象类,它的子类必须重写所有的抽象方法,除非该类也声明为抽象类。

    abstract class Foo{
    	private double c;
    	public Foo(double c){  //没什么意义,需要被子类重写
    		this.c = c;
    	}
    	public abstract double area();  //抽象方法,没有方法体,大括号也不存在
    }
    class Sub extends Foo{
    	public Sub(double c) {  //需要重写构造方法
    		super(c);
    	}
    	public double area(){
    		return 0.0;
    	}
    }
    abstract class Sub2 extends Foo{  //抽象方法继承抽象方法
    	public Sub2(double c) {  //需要重写构造方法,不需要重写抽象方法
    		super(c);
    	}
    }
    

      

    3)抽象类不可以被实例化

    Foo f = new Foo();  //编译错误,抽象类不能被实例化
    

      即使一个类中没有抽象方法,也可以将其定义为抽象类,同样,该类不可以实例化。

      注意:abstract和final关键字不能同时修饰一个类,因为final使得类不可继承,而abstract修饰的类如果不可以继承将没有任何意义。

     

    4)继承抽象类

      一个类继承抽象类后,必须实现其抽象方法,不同的子类可以有不同的实现。

    abstract class Foo{
    	private double c;
    	public Foo(double c){  //没什么意义,需要被子类重写
    		this.c = c;
    	}
    	public abstract String sayHi();
    }
    class Sub extends Foo{
    	public Sub(double c) {  //需要重写构造方法
    		super(c);
    	}
    	public String sayHi(){
    		return "Hello";
    	}
    }
    

      

    4)抽象类的意义

    • 为其子类提供一个公共的类型(父类引用指向子类对象,即向上造型)
    • 封装子类中的重复内容(成员变量和方法)
    • 定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的(子类需要实现此抽象方法)

    案例1:抽象类演示

    public class AbstractDemo {
    	public static void main(String[] args){
    //		Shape s = new Shape(); //编译错误,抽象类不能被实例化
    		Shape[] shape = new Shape[4];  //创建Shape数组对象
    		shape[0] = new Circle(1);  //向上造型
    		shape[1] = new Circle(2);
    		shape[2] = new Square(1);
    		shape[3] = new Square(2);
    		maxArea(shape);  //调用求最大面积方法
    	}
    
    	private static void maxArea(Shape[] shape) {
    		double max = shape[0].area();
    		int maxIndex = 0; //最大面积下标
    		for(int i=0;i<shape.length;i++){
    			double area = shape[i].area();
    			if(area>max){
    				max = area;
    				maxIndex=i;
    			}
    		}
    		System.out.println("最大面积为:"+max+"所在下标为:"+maxIndex);
    	}
    }
    abstract class Shape{ //抽象类---不完整的类
    	protected double c; //周长
    	public abstract double area(); //抽象方法---不完整
    }
    class Circle extends Shape{
    	public Circle(double c){
    		this.c = c;
    	}
    	public double area(){  //重写抽象方法---变不完整为完整
    		return 0.0796*c*c;
    	}
    }
    class Square extends Shape{
    	public Square(double c){
    		this.c = c;
    	}
    	public double area(){
    		return 0.0625*c*c;
    	}
    }
    

      

     

    2. 接口

    • 是一个标准、规范,遵循了这个标准就能干某件事
    • 是一种数据类型(引用类型)
    • 由interface定义,只能包含常量和抽象方法,方法默认由public abstract修饰
    • 接口不能被实例化
    • 接口是需要被实现的,通过implements关键字实现,实现类:必须重写接口中的所有抽象方法
    • 一个类可以实现多个接口,逗号分隔,若又继承又实现,必须先继承后实现
    • 接口可以继承一个或多个接口,逗号分隔(extends)

    1)定义接口

      接口可以看成是特殊的抽象类。即:只包含抽象方法和常量的抽象类。通过interface关键字来定义接口。

    interface Demo{
    	public static int x = 100;
    	public int y = 50;
    	double area();   //默认会加上public abstract修饰
    	public abstract void test();
    }
    

      

    2)实现接口

      与继承不同,一个类可以实现多个接口,实现的接口直接用逗号分隔,该类需要实现这些接口中定义的所有方法。通过implements关键字实现接口。接口可以作为一种类型声明变量,一个接口类型的变量可以引用实现了该接口的类的对象,通过该变量可以调用该接口中定义的方法(具体的实现类提供了方法的实现)。一个接口类型变量,引用了子类的对象,调用时,调用的是子类对象的具体的实现。

    public class Test {
    	public static void main(String[] args){
    		Demo d = new Aoo();   //一个接口类型变量,引用了子类的对象,调用时,调用的是子类对象的具体的实现
    		d.test();   //This is Aoo
    	}
    }
    
    interface Demo{
    	public static int x = 100;
    	public int y = 50;
    	double area();   //默认会加上public abstract修饰
    	public abstract void test();
    }
    class Aoo implements Demo{
    	public double area(){
    		return 0.0;
    	}
    	public void test(){
    		System.out.println("This is Aoo");
    	}
    }
    

      

    3)接口的继承

      接口间可以存在继承关系,一个接口可以通过extends关键字继承另外一个接口,子接口继承了父接口中定义的所有方法。

    interface Foo{
    	public void funFoo();
    }
    interface Goo{
    	public void funGoo();
    }
    interface Hoo extends Foo,Goo{  //接口可以继承一个或多个接口,逗号分隔
    	public void funHoo();
    }
    interface Ioo{
    	void funIoo();
    }
    
    class Joo implements Hoo,Ioo{  //一个类可以继承多个接口
    	public void funFoo(){}  //重写父类的父类的抽象方法
    	public void funGoo(){}  //重写父类的父类的抽象方法
    	public void funHoo(){}  //重写父类的抽象方法
    	public void funIoo(){}   //重写父类的抽象方法
    }
    

      

    4)接口和抽象类的区别

    • 一个类只能继承一个抽象类,但可以实现多个接口
    • 抽象类中可以包含抽象方法和非抽象方法,而接口中的所有方法均为抽象的
    • 子类继承抽象类必须实现抽象类中所有抽象方法,否则子类也必须是抽象类。而子类实现接口则必须实现接口中所有的抽象方法。

     

    案例2:接口的演示

    public class InterfaceDemo {
    	public static void main(String[] args){
    //		Inter6 o1= new Inter6();   //编译错误,接口不能被实例化
    		Inter6 o2 = new Moo();  //向上造型
    		Inter5 o3 = new Moo();
    	}
    }
    //演示接口语法
    interface Inter1{
    	public static final int NUM = 5;
    	public abstract void show();
    	double PI = 3.14; //默认public static final修饰
    	void say();  //默认public abstract修饰
    //	int count; //编译错误,常量必须声明同时初始化
    //	void test(){}  //编译错误,抽象方法没有方法体
    }
    
    //演示接口实现
    interface Inter2{
    	void show();
    	void say();
    }
    class Joo implements Inter2{
    	public void show(){}
    	public void say(){}
    }
    
    //演示接口的多实现、继承
    interface Inter3{
    	void show();
    }
    interface Inter4{
    	void say();
    }
    abstract class Koo{
    	abstract void test();
    }
    class Loo extends Koo implements Inter3,Inter4{
    	public void show(){}
    	public void say(){}
    	void test(){}
    }
    
    //演示接口继承接口
    interface Inter5{
    	void show();
    }
    interface Inter6 extends Inter5{
    	void say();
    }
    class Moo implements Inter6{
    	public void show(){}
    	public void say(){}
    }
    

      

     3. 多态

    1)意义:

      1.1)同一类型的引用指向不同的对象时,有不同的实现:行为的多态:cut()、run()

      1.2)同一个对象被造型为不同的类型时,有不同的功能:对象的多态:水

    2)向上造型:

      2.1)父类型的引用指向子类的对象

      2.2)能造型成为的类有:父类、所实现的接口

      2.3)能点出来什么,看引用的类型

    3)强制类型转换,成功的条件有两种:

      3.1)引用所指向的对象,就是该子类型

      3.2)引用所指向的对象,实现了该接口

    4)若不满足以上两个条件,则发生ClassCastException类型转换异常

      建议:在强转之前先通过instanceof判断引用指向的对象是否是该类型

    4. 成员内部类:应用几率不大

    1)类中套类,里面的成为Inner,外面的成为Outer

    2)内部类通常只服务于外部类,对外不具备可见性

    3)内部类对象通常是在外部类中创建的

    4)内部类中可以直接访问外部类的成员,包括私有的

       一般情况下,Inner对象会在Outer对象中创建(构造方法或其他方法),Inner对象中会有一个隐式的引用指向创建它的Outer类对象,外部类名.this.

    5. 匿名内部类

    1)若想创建一个类(子类)的对象,并且对象只被创建一次,此时该类不必命名,称之为匿名内部类

    2)匿名内部类中访问外部的变量,该变量必须是final的

    常见面试题:内部类有独立的.class吗? 答案:有

    5. 面向对象三大特征

    1)封装:

      1.1)类:封装的是对象的属性和行为

      1.2)方法:封装的是业务逻辑功能的实现

      1.3)访问控制修饰符:封装的是访问的权限

    2)继承:

      2.1)作用:代码复用,通过extends来实现继承

      2.2)父类/基类:共有的

        子类/派生类:特有的

      3.3)单一继承、多接口实现

    3)多态:

      3.1)意义:行为的多态、对象的多态 

      3.2)向上造型、强制类型转换(instanceof)

      3.3)多态的表现形式:重写、重载

     

    设计规则:

    1)将所有子类共有的属性和行为,抽象到父类中

    2)所有子类行为都一样,设计为普通方法

      所有子类行为不一样,设计为抽象方法

    3)将部分子类共有的行为,抽象到接口中

      符合既是也是的原则,使用接口

      接口是对继承的单根性的扩展——实现多继承

     

    案例3:多态的演示

    public class MultiTypeDemo {
    	public static void main(String[] args){
    		Aoo o1 = new Boo();  //向上造型(自动类型转换)
    		Boo o2 = (Boo)o1;     //o1指向的对象就是Boo类型(强制类型转换)
    		Inter o3 = (Inter)o1;    //o1指向的对象实现了Inter接口(强制类型转换)
    //		Coo o4 = (Coo)o1;    //java.lang.ClassCastException:类型转换异常
    		if(o1 instanceof Coo){  //强转建议使用instanceof判断
    			Coo o5 = (Coo)o1;
    		}
    	}
    }
    
    interface Inter{}
    class Aoo{}
    class Boo extends Aoo implements Inter{}
    class Coo extends Aoo{}

    案例4:多态的演示2

    public class UnionPayTest {
    	public static void main(String[] args) {
    		ABCATM atm = new ABCATM(); //atm机对象
    		UnionPay card = new ABCImpl(); //银联卡
    		atm.insertCard(card); //插卡
    		atm.payTelBill(); //支付电话费
    	}
    }
    class ABCATM{ //农行ATM机类
    	private UnionPay card; //银联卡
    	public void insertCard(UnionPay card){ //插卡
    		this.card = card;
    	}
    	public void payTelBill(){ //支付电话费按钮
    		if(card instanceof ABC){ //是农行卡
    			ABC abcCard = (ABC)card; //强转为农行卡
    			abcCard.payTelBill("12345679845", 500);
    		}else{ //不是农行卡
    			System.out.println("不是农行卡,不能支付电话费");
    		}
    	}
    }
    
    interface UnionPay{ //银联接口
    	public double getBalance(); //查询余额
    	public boolean drawMoney(double number); //取款
    	public boolean checkPwd(String input); //验证密码
    }
    interface ICBC extends UnionPay{ //工行接口
    	public void payOnline(double number); //在线支付
    }
    interface ABC extends UnionPay{ //农行接口
    	public boolean payTelBill(String phoneNum,double sum); //支付电话费
    }
    
    class ICBCImpl implements ICBC{ //工行卡
    	public double getBalance(){return 0.0;}
    	public boolean drawMoney(double number){return true;}
    	public boolean checkPwd(String input){return true;}
    	public void payOnline(double number){}
    }
    class ABCImpl implements ABC{ //农行卡
    	public double getBalance(){return 0.0;}
    	public boolean drawMoney(double number){return true;}
    	public boolean checkPwd(String input){return true;}
    	public boolean payTelBill(String phoneNum,double sum){
    		System.out.println("支付电话费成功");
    		return true;
    	}
    }
    

    案例5:成员内部类的演示

    public class InnerClassDemo {
    	public static void main(String[] args){
    		Outer outer = new Outer(100);
    		outer.printTime();
    		//		Inner g = new Inner();   //编译错误
    	}
    }
    
    class Outer{
    	private int time;
    	private Inner inner;
    	Outer(int time){
    		this.time = time;
    		inner = new Inner();
    		inner.timeInc();
    	}
    	public void printTime(){
    		System.out.println(Outer.this.time);   //101
    		System.out.println(++time);  //102
    	}
    	class Inner{
    		public void timeInc(){
    			time++;
    		}
    	}
    }
    

      在Outer构造方法中创建的Inner对象会有一个隐式的引用指向创建它的Outer对象,调用Inner对象的timeInc方法,即会对Outer的time属性进行操作。

    案例6:匿名内部类的演示

     

    public class NstInnerClassDemo {
    	public static void main(String[] args){
    		/*
    		 * 1)创建了Inter2的一个子类,但是没有名字
    		 * 2)为该子类创建了一个对象,叫o1
    		 * 3)大括号中的为子类的类体
    		 */
    		Inter2 o1 = new Inter2(){	};
    		
    		/*
    		 * 1)创建了Inter2的一个子类,但是没有名字
    		 * 2)为该子类创建了一个对象,叫o2
    		 * 3)大括号中的为子类的类体
    		 */
    		Inter2 o2 = new Inter2(){ };
    		
    		int num = 5;
    		/*
    		 * 1)创建了Inter1的一个子类,但是没有名字
    		 * 2)为该子类创建了一个对象,叫o3
    		 * 3)大括号中的为子类的类体
    		 */
    		Inter1 o3 = new Inter1(){
    			public void show(){
    				System.out.println("show");
    				System.out.println(num);
    			}
    		};
    		o3.show();
    	}
    }
    
    interface Inter1{
    	void show();
    }
    interface Inter2{ }
    

      

     

     

     

  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/jmwm/p/7011610.html
Copyright © 2011-2022 走看看