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{ }
    

      

     

     

     

  • 相关阅读:
    Spring配置文件中关于Shiro的配置
    关于Realm的源码分析
    配置SpringMVC配置
    Shiro的登录验证及授权多Realm情况【基于SpringMVC框架下】
    关于Nginx配置说明
    Hibernate中No row with the given identifier exists问题的原因及解决
    关于Shiro的角色授权
    关于Shiro的认证策略
    关于hibernate的cache总结及并发问题
    Shiro多Realm数据交互实现过程
  • 原文地址:https://www.cnblogs.com/jmwm/p/7011610.html
Copyright © 2011-2022 走看看