Java第七章:面向对象高级特性

  • 继承

    • 含义:在Java中定义一个类时,让该类通过关键字extends继承一个已有的类,这就是类的继承(泛化)。
      被继承的类称为父类(超类,基类),新的类称为子类(派生类)。
      子类继承父类的所有属性和方法,同时也可以增加自己的属性和方法

    • 语法: 子类 extends 父类

    • 好处

      • 使编码更高效
      • 易维护
      • 代码的重用
    • 作用:

      • 提高代码复用率
      • 子类继承父类,子类扩展父类功能(扩展功能)
    • 注意:

      ​ ①子类继承父类继承了父类的属性和方法,也能有自己的属性和方法,简单来说子类在父类的基础上做了扩展

      ​ ②子类访问父类中的属性和方法受到访问修饰符的限制,比如 private修饰的属性,子类不能访问

      ​ ③Java中只支持单继承,也就是说每个类只能有一个直接父类,不允许有多重继承

      ​ ④一个类可以是另一个类的父类或间接父类

      ​ ⑤一个类可以有多个子类

      ​ ⑥父类不能访问子类的属性和方法

    • 子类实例化过程

      • 父类的静态代码块–子类静态代码块–父类的构造代码块–父类构造器–子类构造代码块–子类构造器
      /**
       * 子类实例化过程:先初始化化父类再初始化子类,最后完成子类的创建(先调用父类的构造方法再调用子类的构造方法)
       *       父类的静态代码块--子类静态代码块--父类的构造代码块--父类构造器--子类构造代码块--子类构造器
       * @author Administrator
       *
       */
      public class Cat extends Animal{
      	String color;
      	
      	{
      		System.out.println("Cat 的构造代码块");
      	}
      	
      	static {
      		System.out.println("Cat 的静态代码块 ");
      	}
      	public Cat() {
      		System.out.println("Cat 的构造方法");
      	}
      
      }
      
      
  • this和this()

    /**
     * this和this()
     * 	this:当前实例化对象
     * 	this([参数]):当前类的构造器
     * 		①当this([参数])中不带参数时调用的是无参构造方法,根据参数判断调用的构造方法
     * 		②this([参数])只能在构造器中被调用
     * 		③对象的初始化只需要让一个构造器完成,所以一个构造方法中只能调用一个this([参数])
     * 		④this([参数])在被调用时一定在构造器第一行
     * 
     * @author Administrator
     *
     */
    public class Animal {
    	int age;
    	int sex;
    	public Animal() {
    //		this(20);
    //		this(20,2);
    		System.out.println("Animal 无参构造方法");
    		
    	}
    	public Animal(int age) {
    		System.out.println("Animal 有参构造方法"+"age:"+age);
    		this.age=age;
    	}
    	public Animal(int age,int sex) {
    		System.out.println("Animal 有参构造方法"+"age:"+age+" sex:"+sex);
    		this.age=age;
    		this.sex=sex;
    	}
    //	成员方法
    	public void getAge() {
    //		this();编译不通过
    	}
    
    	@Override
    	public String toString() {
    		return "Animal [age=" + age + ", sex=" + sex + "]";
    	}
    	public static void main(String[] args) {
    //		Animal a1=new Animal();
    //		System.out.println(a1);
    		
    //		Animal a2=new Animal(20);
    //		System.out.println(a2);
    
    		
    	}
    
    }
    
  • super和super()

/**
 * super和super()
 * 		super:父类引用,父类在内存中的地址
 * 		         可以通过super对父类中的属性进行赋值
 * super([参数]):父类构造器
 * 				①super([参数])中不带参数时调用的是父类无参构造方法,根据参数判断调用的构造方法
 * 				②因为调用子类构造器时必定先调用父类构造器,所有当子类中没有使用super([参数]),
 * 					编译器默认在其第一行加上super()无参的父类构造器
 * 				③如果父类中没有无参构造器,那么子类中声明的构造器就会编译报错
 * 					解决方案:①在子类构造器中显示的调用父类中已有的构造方法
 * 							②在父类中提供无参构造方法(建议)
 * 
 * 				④super([参数])一定在构造器的第一行
 * 				⑤super()和this()不能同时声明在同一个构造其中
 * 				⑥如果构造方法中有了this(),编译器就不会默认加上super()
 * @author Administrator
 *
 */
public class Cat extends Animal{
	String color;
	public Cat() {
//		super();
		this("红色");
//		super(20);
		System.out.println("Cat 的构造方法");
		
	}
	public Cat(String color) {
//		super();
		System.out.println("Cat 有参的构造方法"+color);
		this.color=color;
	}
	public Cat(String color,int age,int sex) {
		super(age,sex);
		this.color=color;
//		super.age=age;
//		super.sex=sex;
//		this.age=age;
//		this.sex=sex;
	}
	
	@Override
	public String toString() {
		return "Cat [color=" + color + ", age=" + super.age + ", sex=" + sex + "]";
	}
	public static void main(String[] args) {
//		Cat c=new Cat();
//		如果我想在子类实例化的同时完成属性的赋值,包括子类用到的父类的属性--使用有参的构造方法
		Cat c=new Cat("红色",10,2);
		System.out.println(c);
		
//		Cat c1=new Cat();
//		System.out.println(c1);
	}

}
  • 封装

    • 概述:就是将不想或不该告诉他人的东西隐藏起来,将可以告诉他人的内容公开(隐藏对象的属性和方法的实现细节,只公开对外接口)

    • 好处

      • 隐藏实现的细节
      • 方便修改的实现
      • 只能通过规定方法访问
      • 避免不合法数据的输入
    • 四个访问修饰符*(java中封装性的体现):public > protected > default > private

      privatedefaultprotectedpublic
      同一个类
      同一个包中的类×
      不同包中的类×××
      不同包中的子类××
      • 注意protected 修饰的属性和方法能被子类访问,我们应该实例化子类,使用子类引用访问而不是实例化父类
  • 修饰符的使用(封装的具体应用)

    • 构造器和类的权限通常为public

    • 一般把属性设为private,让其他类不能直接访问属性,达到保护属性的目的

    • 不使用权限修饰符时(即default)的成员在类内以及在同一个包中的其他类可以访问

    • protected所修饰的成员在类内、同一个包中、所在类的子类中都可以访问

      **
       * 给属性赋值的方式:
       * 		①通过构造方法
       * 		②通过set方法
       * 
       * @author Administrator
       *
       */
      public class Emp {
      //	属性私有
      	private int age;
      	private String name;
      	private String address;
      	
      	
      	public Emp(int age, String name, String address) {
      		super();
      		this.age = age;
      		this.name = name;
      		this.address = address;
      	 }
      	
      
      	public Emp() {
      		super();
      	}
      	
      
      	public int getAge() {
      		return age;
      	}
      
      
      	public void setAge(int age) {
      		if(140<age || age<18) {
      //			如果年龄输入不合适给默认值为20
      			this.age=20;
      		}else {
      			this.age=age;
      		}
      //
      	}
      
      
      	public String getName() {
      		return name;
      	}
      
      
      	public void setName(String name) {
      		this.name = name;
      	}
      
      
      	public String getAddress() {
      		return address;
      	}
      
      
      	public void setAddress(String address) {
      		this.address = address;
      	}
      
      
      	//
      //	//	提供共有的访问属性的方法
      //	public void setAge(int age) {
      //		if(140<age || age<18) {
      			如果年龄输入不合适给默认值为20
      //			this.age=20;
      //		}else {
      //			this.age=age;
      //		}
      //		
      //	}
      //	
      //	public int getAge() {
      //		return age;
      //	}
      	@Override
      	public String toString() {
      		return "Emp [age=" + age + ", name=" + name + ", address=" + address + "]";
      	}
      
      
      }
      
  • 方法重写

/**
 * 方法的重载:
 * 		前提:必须在同一个类中
 * 		规则:一同一不同
 * 			方法名相同参数列表不同
 * 			返回值可同可不同
 * 
 * 方法的重写(方法的覆盖):是对从父类中继承来的方法进行改造,只有在子类继承父类时发生。
 * 前提:必须有继承或者实现
 * 规则:
 * 	 重写的方法名要和被重写的方法名相同
 * 	 参数列表相同
 * 	 返回值类型相同
 * 	子类覆盖方法的访问权限要不小于父类中被覆盖方法的访问权限
 * 
 *注意: 	 
 *	①当子类中的方法名和参数列表与父类中的方法一致时,编译器就认为该方法为重写的方法
 * 	②子类引用调用重写的方法时执行的是子类重写父类的方法
 *  ③可以使用@Override注解修饰重写的方法,告诉编译器该方法是重写的方法
 * 	④final、static、private 修饰的方法不能被重写
 * 	
 * @author Administrator
 *作用:
 *	①体现行为的多态性:同一个方法有不同的实现
 *	②提高代码的复用率
 *	③使代码结构变得清晰
 *	④子类增强父类中方法的功能
 	⑤方便功能的扩展
 *	
 */
public class Animal {
	
	public void eat() {
		System.out.println("Animal 动物吃");
	}
	
	public String sleep() {
		System.out.println("Animal 动物睡觉");
		return "Animal 睡得香";
	}
	public String sleep(String name) {
		System.out.println("Animal 动物睡觉");
		return "Animal 睡得香";
	}
	
	protected void play() {
		System.out.println("Animal 玩的开心");
	}
	
//	private void play() {
//		System.out.println("Animal 玩的开心");	
//	}
	

}
  • final关键字

    /**
     * final关键字:
     * 		①修饰方法不能被重写
     * 		②修饰的类不能被继承
     * 		③修饰的变量不能第二次赋值
     * 			1、局部变量
     * 			2、修饰成员变量和静态变量时需要给其赋初始值,因为系统不会对final属性默认的赋初始值
     *变量:在程序运行过程中随时可能发生改变的量 	
     * 常量:在程序运行过程中一直不变的量   [访问修饰符] fianl static int age;
     * 	
     * 		
     * @author Administrator
     *
     */
    public  class Student {
    //	final int age=20;
    //	final static int age=20;
    	final static int  sex=10;
    	private final static int age=20;
    	
    	
    	public static void main(String[] args) {
    		final int a;
    		a=10;
    		System.out.println(a);
    		Student s=new Student();
    		System.out.println(s.age);
    		Student s1=new Student();
    		System.out.println(s1.age);
    
    		
    		
    	}
    
    }
    
  • 抽象方法和抽象类

    /**
     * abstract(抽象):
     * 		1、修饰方法:抽象方法
     * 			①抽象方法没有方法具体的实现,简单来说就是没有方法体
     * 			②抽象方法是用来被重写的,所有不能使用static、fianl、private修饰抽象方法
     * 			③为什么要声明抽象方法:当你不知道某个方法具体的实现(这个方法的功能实现多种多样),就可以将该方法声明成抽象方法
     * 		2、修饰类:抽象类
     * 			①一个类中有一个或多个抽象方法时,该类必然要声明成抽象类
     * 			②抽象类就是用来被继承的,所有抽象类不能用fina关键字修饰
     * 			③当一个类继承了抽象类,必然实现抽象类中的所有抽象方法,不然就声明成抽象类
     * 			④抽象类不能被实例化
     * 			⑤抽象类中的成员:
     * 				既能声明抽象方法也能声明非抽象方法
     * 				可以全都是抽象方法也可以全都是非抽象方法
     * 				***抽象类中除了能包含普通类中所有的成员外还能有抽象方法
     * 
     * 		    ⑥抽象类中有构造方法
     * 		3、什么时候一个类会被声明成抽象类
     * 			①当一个类中有抽象方法时
     * 			②当一个类继承抽象类没有实现(重写)完抽象类中的所有抽象方法时
     * 			③当一个类实现一个接口,并且不能为全部抽象方法都提供实现时;
     * @author Administrator
     *
     */
    public  abstract class Animal {
    //	成员变量
    	String name;
    //	静态变量
    	static int age;
    	
    //	构造器
    	public Animal() {
    		System.out.println("Animal 的构造器");
    	}
    	
    //	抽象方法
    	public  abstract void eat();
    	public  abstract void sleep();
    	
    //  成员方法:由子类调用
    	public void getName() {
    		System.out.println("Animal getName"+name);
    	}
    //	静态方法
    	public static void getAge() {
    		System.out.println("Animal getAge");
    	}
    	
    	public static void main(String[] args) {
    		Animal.getAge();
    		
    	}
    
    }
    
  • 接口

    • 概述:Java继承时一个类只有一个直接父类,也就是单继承,但是一个类可以实现多个接口,接口弥补了类的不能多继承缺点,继承和接口的双重设计既保持了类的数据安全也变相实现了多继承。

      /**
       * 动物接口
       * 接口的意义:变相的实现了多继承,一个类只能继承一个父类,但是可以实现多个接口
       * 			接口中都是行为动作,所以接口就是一套行为协议
       * @author Administrator
       * 	注意:
       * 		①接口不是类,没有构造方法,不能实例化
       * 		②接口中只能声明静态方法和抽象方法,jdk1.8之后有默认的方法
       * 		③接口中不能有成员变量,只有常量默认修饰为  public final static 数据类型 常量名  访问修饰符只能是public
       * 		④接口中的抽象方法默认修饰为 public abstract 返回值 方法名();  访问修饰符只能是public
       *
       *  接口中的成员:常量、静态方法、抽象方法、默认的方法
       *  
       *  接口的使用:
       *  	①接口就是用来被实现的,一个类实现接口必然实现(重写)接口中所有的抽象方法   class 类名 implements 接口名
       *  	②一个类能实现多个接口的同时继承一个类
       *  	③接口可以实现多继承:一个接口继承其他接口该接口就拥有其他接口的所有抽象方法
       *  		[修饰符]  interface   接口名 extends 接口1,接口2{接口的成员 }                    
                          
      
       *  接口和类的关系:
       *  	类用来实现接口
       *  	如果一个类要实现一个接口,那么这个类就必须实现接口中所有抽象方法。否则这个类只能声明为抽象类
       *  	多个无关的类可以实现一个接口,一个类可以实现多个无关的接口
      	
      	
       * 接口的作用:
       * 	     结构化设计中提倡高内聚低耦合,如果程序的耦合度高不利于功能的扩展和后期的维护
       * 		内聚:模块内各个组件之间联系的紧密程度 
       * 		耦合:模块与模块之间联系的紧密程度
       * 	     **降低模块间或系统间的耦合性(解耦)
       */
      public interface Animal {
      	
      	
      	int age=20;  // public final static  int age=20
      	
      	public int sex=30;// public final static  int sex=20
      
      	
      	public static void getName() {
      		System.out.println("接口中的静态方法");
      	}
      /*	public void setName() {
      		编译错误
      	}*/
      	public abstract void getAge() ;
      	
      	String eat(); //public abstract String eat()
      	
      	public void sleep(int mills); 
      	
      	
      	public static void main(String[] args) {
      		Animal.getName();
      	}
      	
      
      }
      
  • 接口和抽象类的对比:

    • 接口不能含有任何非抽象方法,而抽象类可以。
    • 类可以实现多个接口,但只能有一个父类。(接口可以多实现,类只能单继承)
    • 接口和接口之间可以多继承
    • 抽象类可以理解为抽象方法和非抽象方法的混合体,而接口中的方法完全是抽象方法,是一套纯粹的行为规范
      • 面试:接口中都是抽象方法,但是可以有静态方法和默认方法 默认方法是在jdk1.8之后才有 抽象类既可以包含抽象方法,也可以包含非抽象方法
  • 什么时候声明成抽象类?什么时候声明成接口?

    当你想类中有抽象方法又想要有自己具体的功能时可以声明成抽象类,当你想定义一套行为你规范时可以声明成接口,但接口可以多实现

  • 向上塑型和向下塑型

    /**
     * 向上塑型: 父类引用(对象)指向子类实例	
     * 前提 — 具有继承或实现关系
     * 		 ①引用.重写的方法执行的是子类重写父类的方法
     * 		 ②向上转换损失了子类新扩展的属性和方法,仅可以使用从父类中继承的属性和方法
     * 	     ③子类转换为父类,自动转换
     * 向下塑型:必须先向上塑型才能向下塑型
     * 		如果想用子类自有的属性和方法那么需要向下塑型
     * 		强制转换
     * 
     * @author Administrator
     *
     */
    public class Test {
    
    	public static void main(String[] args) {
    
    /*		Dog d=new Dog();
    		d.eat();
    		d.dealer();*/
    		
    //		Biological b=new Crow();
    //		b.breathing();
    		
    //		向上塑型: 父类引用(对象)指向子类实例	
    		Animal dog1=new Dog(); //狗是动物
    		dog1.eat();
    		
    //		向下塑型:必须先向上塑型才能向下塑型
    		Animal a=new Animal();
    //		Cat cat1=(Cat) a;//编译通过 Animal cannot be cast to Cat
    		Animal cat=new Cat();
    		cat.getAge();//父类没有被重写的方法  Animal getAge
    		cat.eat();//执行子类重写父类的方法 Cat eat
    		
    
    //		如果想用子类自有的属性和方法那么需要向下塑型
    		Cat cat1=(Cat) cat;
    		cat1.catchmice();//自有的方法恢复 Cat 抓老鼠
    		
    //		Dog dog2=(Dog) cat;//编译通过 Cat cannot be cast to Dog
    		
    	}
    
    }
    
  • 多态

    • 概述:简单来说,多态是具有表现多种形态的能力的特征

    • 行为的多态

    • 对象的多态

    • 类的多态

      • 行为的多态导致对象的多态,对象的多态导致类的多态
    • 多态的前提条件

      • 必须有继承或者实现
      • 必须有方法的重写
      • 向上塑型(体现多态性)
    • 多态的优点
      简化代码
      改善代码的组织性和可读性
      易于扩展

  • instanceof

    • 判断一个实例对象是否属于一个类
      object instanceof class
    • 判断一个类是否实现了某个接口
      object instanceof interface
    • 返回值都是boolean类型
  • 内部类

    • 概述:类中再定义类,内部类对于同一包中的其它类来说,内部类能够隐藏起来。

      • 语法:

        • [访问权限修饰符]  class  类名{                          
            [访问权限修饰符]  class  类名{                          
                内部类成员
            }
            外部类成员
          }
          外部类的访问修饰符:default public
          内部类的访问修饰符能是default public  protected private
          
          
    • 成员内部类

    • 静态内部类

    • 局部内部类

    • 匿名内部类

      /**
       * 内部类:当一个类中的方法不足以完成某些功能又不想新建一个外部类完成时使用内部类
       * @author icekingdom
       * 	成员内部类:
       * 			①在成员内部类中只能声明成员变量和成员方法(非静态资源),但是不能声明静态资源、
       * 			②成员内部类能访问外部类的所有静态资源和非静态资源
       * 
       * 静态内部类:
       * 		  ①静态内部类中能声明静态资源和非静态资源
       * 		  ②静态内部类只能访问外部类的静态资源,但是不能访问非静态资源
       * 		  
       *局部内部类:
       *		局部内部类特点:
       *			在一个类的方法体中或程序块内定义的内部类
       *			在方法定义的内部类中只能访问方法中的final类型的局部变量
       *
       *匿名内部类:
       *	没有定义类名的内部类,称为匿名内部类
       *	匿名内部类特点:
      		匿名内部类没有访问修饰符。
      		new 匿名内部类,这个类首先是要存在父类或接口。
      		外部类方法形参或局部变量需要被匿名内部类使用,必须为final
       *           语法:
       *		         new 父类|接口(){    
       *                重写父类或接口的抽象方法
       *                } 
       *		
       */
      public class Student {
      //	静态变量
      	static int age;
      //	成员变量
      	int sex=20;
      //	成员方法
      	public void show() {
      		System.out.println("成员方法show ");
      	}
      //	静态方法
      	public static void get() {
      		System.out.println("静态方法get ");
      	}
      	
      
      	public void getResult(int i) {
      		final int a=20;//默认加上final
      //		a=30;
      //		局部内部类
      		class LocalInnerClass{
      			public String show() {
      				System.out.println("局部内部类"+a);
      				return "zhangsan";
      			}
      		}
      		LocalInnerClass lic=new LocalInnerClass();
      		String ss=lic.show();
      		System.out.println(ss);
      		
      	}
      	
      	
      //	成员内部类
      	class Innerclass{
      		String icname;
      //		static int m; 编译报错
      		int sex=10;
      		public void showAll() {
      			show();
      			get();
      			System.out.println("成员内部类showAll"+icname);
      		}
      		public void getName() {
      //			showAll();
      //			如果内部类和外部类中的变量同名时,调用的是内部类的变量,要想调用外部类的变量使用 [外部类.this]区分
      //			System.out.println("成员内部类getName"+sex);
      			System.out.println("成员内部类getName"+Student.this.sex); 
      			System.out.println("成员内部类getName"+Student.age); 
      		}
      	}
      //	静态内部类
      	static class StaticInnerClass{
      		String address;
      		static int id;
      		public void showAll(){
      			System.out.println("静态内部类showAll"+age);
      		}
      		public static void getName(){
      			System.out.println("静态内部类getName"+id);
      		}
      	}
      	public static void main(String[] args) {
      //		访问成员内部类:先实例化外部类再实例化内部类
      //		Student s=new Student();
      //		Innerclass ic=s.new Innerclass();
      //		Innerclass ic=new Student().new Innerclass();
      //		ic.showAll();
      //		ic.getName();
      //		访问静态内部类:通过类名实例化内部类
      //		StaticInnerClass sic=new Student.StaticInnerClass();
      //		sic.getName(); //静态内部类getName0
      //		Student.StaticInnerClass.getName(); //静态内部类getName0
      //		s.getResult(20); //局部内部类
      		
      //		匿名内部类在方法中使用抽象类或者接口行为
      		Animal a=new Animal() { //创建匿名内部类
      			
      			@Override
      			public void getName(int i) {
      				System.out.println("匿名内部类"+i);
      				
      			}
      		};
      		a.getName(20); //匿名内部类20
      		
      	}
      
      
    • Lambda表达式

      /**
       * 函数式接口:只能有一个抽象方法
       * @author Administrator
       *
       */
      @FunctionalInterface
      public interface Animal {
      //	public void getName(int i);
      	
      //	public void getAge(int i,String x);
      	
      //	public void  getAge();
      	
      	public String getName(int no);
      }
      
      
      public class TestLambda {
      
      	public static void main(String[] args) {
      //		匿名内部类
      /*		Animal a=new Animal() {
      			@Override
      			public void getName(int s) {
      				System.out.println("匿名内部类"+s);
      				
      			}
      		};
      		a.getName(20);*/
      //		Lambda表达式:允许我们将接口中的行为传到函数里
      		/*
      		 * 语法:
      		 * 	([参数])->{代码块}
      		 *  一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数 
      		 *  一个箭头符号:-> 
      		 *  方法体,可以是表达式和代码块。
      		 *  接口只包含一个方法可以使用@FunctionalInterface注解
      		 */
      //		public void getName(int i); 单参无返回值
      		/*Animal aa=(s)->{
      			System.out.println("Lambda表达式"+s);
      			
      		};
      		
      		aa.getName(10);*/
      //		public void getAge(int i,String x); 多参无返回值
      		/*Animal aa=(i,x)->{
      			System.out.println("Lambda表达式"+i+","+x);
      		};
      		aa.getAge(20, "zhangsan");*/
      		
      //		public void  getAge();  无参无返回值
      		/*Animal aa=()->{
      			System.out.println("Lambda表达式");
      		};
      		aa.getAge();*/
      		
      //		public String getName(int no);
      		Animal aa=(s)->{
      			System.out.println("Lambda表达式"+s);
      			return "zhangssan";
      			
      		};
      		String name=aa.getName(20);
      		System.out.println(name);
      	}
      
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值