黑马程序员_JavaSE基础知识总结九:多态、包、import和内部类

------ android培训java培训、期待与您交流! ----------


多态其实就是多种状态的含义,如我们方法重载,相同的方法名称可以完成不同的功能,这就是多态的一种表现,此时成为静态多态。另外就是我们将学生保存到数据的示例,当我们调用Istudent 接口中的方法,那么java 会自动调用实现类的方法,如果是Oracle 实现就调用Oracle 的方法,如果是MySql 实现就调用MySql 中的方法,这是在运行期决定的。多态的条件是:有继承或实现,有方法覆盖或实现,父类对象(接口)指向子类对象

 

一、多态知识总结

1、多态的前提

①有继承或实现;

②有方法覆盖或实现;

③父类对象(接口)指向子类对象

2、多态的好处与弊端

好处:提高代码的维护性(继承保证);提高代码的扩展性(多态保证)。

<span style="font-size:18px;color:#666666;">class Animal{
	public void eat(){
	   System.out.println("Hello 吃!");
	}

	public void sleep(){
	  System.out.println("Hello 睡!");
	}

	public void play(){
	
	  System.out.println("Hello 玩!");
	}
}

class Cat extends Animal{
   public void eat(){
	   System.out.println("猫吃鱼!");
	}

	public void sleep(){
	  System.out.println("猫蜷着睡!");
	}

	public void play(){
	
	  System.out.println("玩毛线!");
	}
}
class Dog extends Animal{
	public void eat(){
	   System.out.println("狗吃骨头!");
	}

	public void sleep(){
	  System.out.println("狗趴着睡");
	}

	public void play(){	
	  System.out.println("狗玩猫");
	}
}
class DuoTaiDemo2{
	public static void main(String[] args) {
		//我想养猫
        Cat c = new Cat();
		//c.eat();
		//c.sleep();
		//c.play();
		//show(c);
		AnimalTools.show(c);
		//觉得一只猫太孤单,又来了一个伴
		Cat c2 = new Cat();
		//c2.eat();
		//c2.sleep();
		//c2.play();
		//show(c2);
		AnimalTools.show(c2);
		//它们产了一只小猫
		Cat c3 = new Cat();
		//c3.eat();
		//c3.sleep();
		//c3.play();
		//show(c3);
		AnimalTools.show(c3);
		//这时 发现代码重复的太多了 ?

		System.out.println("---又想养狗了---------------------");
		Dog d = new Dog();
		//show(d);
		AnimalTools.show(d);
		Dog d2 = new Dog();
		//show(d2);
		AnimalTools.show(d2);
		Dog d3 = new Dog();
		//show(d3);
        AnimalTools.show(d3);
		//DuoTaiDemo2  这是一个测试类,测试类一般写main方法,所以 我不喜欢功能的代码写在测试类里
		//怎么办 这是不是都是对动物进行的操作  是不是可以写一个工具类 里面放这些动物的show()方法

		//我还想养老虎 怎么办  老虎继承动物类  ,老虎在重写那些功能,在工具类里写一个老虎的show() 创建对象,调用show();
		//工具类来回做操作 好吗?
		//怎么办 想一次写好  
	}
   /*
	//写个show方法,看一下一只猫都能干什么
	public static void show(Cat c){
	    c.eat();
		c.sleep();
		c.play();
	}

	public static void show(Dog d){
	    d.eat();
		d.sleep();
		d.play();
	}
	*/
}
//动物操作工具类
class AnimalTools{

	public static void show(Animal a){
// 传递过来的是c =new Cat(); c是猫的对象 猫是动物的子类
	                              //       Animal a  = c;  Animal a  = new Cat();多态的体现
      a.eat();
	  a.sleep();
	  a.play();
	}
	/*
   public static void show(Cat c){
	    c.eat();
		c.sleep();
		c.play();
	}

	public static void show(Dog d){
	    d.eat();
		d.sleep();
		d.play();
	}
	*/
 }</span>

上图中的代码在没有使用多态前异常复杂,引入多态之后代码变得相当简化,又扩展了一些新功能,体现了多态对代码的维护性和扩展性。

弊端:父类不能访问子类的特有功能。

3、多态的表现形式

①向上转型: 父类引用指向子类对象  Fu f = new Zi();  相当于基本数据类型的自动转换 

②向下转型: 将一个父类引用转换成子类引用  Zi z = (Zi)f;前提:该父类引用必须是指向该子类对象的。

<span style="font-size:18px;color:#666666;">class Fu{
	int age = 50;
	String name = "王健林";
	public void house(){
	   System.out.println("一座101层大楼!");
	}
}
class Zi extends Fu{
	String name = "王思聪";
	int age = 25;
   public void house(){
	   System.out.println("给51层!");
	}
   public void netManager(){
      System.out.println("网管!");
   }
}
class NvEr extends Fu{
	String name = "王冬梅";
	int age = 21;
    public void house(){
	   System.out.println("给50层!");
	}
	public void show(){
	   System.out.println("参加车展!");
	}
}
class DuoTaiDemo3{
	public static void main(String[] args) {
		//健林病了,但是有合约要签
		Fu f = new Zi();//王思聪代替他爹去签合约   向上转型
        System.out.println(f.name);//王健林的名字
		f.house();
        //f.netManager();//能去当网管吗?爹是不能当网管的
		Zi z = (Zi)f;//换回自己的身份  向下转型
		z.netManager();
        
        /*
		  Exception in thread "main" java.lang.ClassCastException: Zi cannot be cast to NvEr
        at DuoTaiDemo3.main(DuoTaiDemo3.java:52)
		*/
	   // NvEr nv = (NvEr)f;//向下转型

	}
}</span>

4、多态中成员访问特点

 ①成员变量 :  编译看左边,(=的左边),运行看左边  成员变量的特点:加载到堆内存中了

 ②成员方法 :  编译看左边,运行看右边            方法存在重写,不调用不执行

 ③静态成员方法:  随着类的加载而加载,与对象无关,编译看左边,运行看左边

 ④构造方法:   子类创建对象的时候,先加载父类的构造,再加载子类构造


5、一道经典案

<span style="font-size:18px;color:#666666;">/*	教练和运动员案例(学生分析然后讲解)
		乒乓球运动员和篮球运动员。
		乒乓球教练和篮球教练。
		为了出国交流,跟乒乓球相关的人员都需要学习英语。
		请用所学知识:
		分析,这个案例中有哪些抽象类,哪些接口,哪些具体类。

*/
//学习英语接口
interface StudyEnglish{
	public abstract void study();
}
//定义人类
abstract class Person{
	private String name;
	private int age;

	public Person(){}

	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}

	public void setName(String name){
	    this.name = name;
	}
	public void setAge(int age){
		this.age = age;
	}

	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}

	public abstract void eat();

	public void sleep(){
	  System.out.println("晚安,洗洗睡吧");
	}
	public void show(){
	  System.out.println(name+"---"+age);
	}
}
//定义教练类
abstract class Coach extends Person{
	public Coach(){}

	public Coach(String name,int age){
	    super(name,age);
	}

	public abstract void teach();
}
//定义篮球教练
class BBCoach extends Coach {
	public BBCoach(){}
    
	public BBCoach(String name,int age){
	    super(name,age);
	}
    //重写抽象方法
	public void teach(){
	   System.out.println("教打篮球");
	}

	public void eat(){
	   System.out.println("吃牛肉,喝牛奶");
	}
}
//定义乒乓球教练
class PPCoach extends Coach implements StudyEnglish{
	public PPCoach(){}

	public PPCoach(String name,int age){
	   super(name,age);
	}

	//重写方法
	public void teach(){
	   System.out.println("教打乒乓球");
	}

	public void eat(){
	   System.out.println("吃羊肉,喝羊奶");
	}
	//你实现了接口就要重写接口中的方法
	public void study(){
	  System.out.println("学英语是出国的前提");
	}
}
class InterfaceTest2{
	public static void main(String[] args) {
		//创建一个篮球教练
		BBCoach bb = new BBCoach("宫鲁鸣",55);
		bb.teach();
		bb.eat();
		bb.sleep();
		bb.show();
        //bb.study();
		//创建一个乒乓球教练
		PPCoach pp = new PPCoach("刘国梁",45);
		pp.study();
		pp.show();
	}
}
</span>



二、类之间的关系

泛化关系,类和类之间的继承关系及接口与接口之间的继承关系

实现关系,类对接口的实现

关联关系,类与类之间的连接,一个类可以知道另一个类的属性和方法,在java 语言中使用成员变量体现

聚合关系,是关联关系的一种,是较强的关联关系,是整体和部分的关系,如:汽车和轮胎,它与关联关系不同,关联关系的类处在同一个层次上,而聚合关系的类处在不平等的层次上,一个代表整体,一个代表部分,在java 语言中使用实例变量体现

合成关系,是关系的一种,比聚合关系强的关联关系,如:人和四肢,整体对象决定部分对象的生命周期,部分对象每一时刻只与一个对象发生合成关系,在java 语言中使用实例变量体现

依赖关系,依赖关系是比关联关系弱的关系,在java 语言中体现为返回值,参数,局部变量和静态方法调用

is-a、is-like-ahas-a关系

<span style="font-size:18px;color:#666666;">// is-a关系
public class Animal {
	public void method1();
}

public class Dog extends Animal { // Dog is a Animal
}

// is-like-a关系
public interface I {
	public void method1();
}

public class A implements I { // A is like a I;
	public void method1() {
		// 实现
	}
}

// has-a关系
public class A { // A has a B;
	private B b;
}

public class B {
}</span>





三、包和import

1、

包其实就是目录,特别是项目比较大,java 文件特别多的情况下,我们应该分目录管理,java 中称为分包管理,包名称通常采用小写

<span style="font-size:18px;color:#666666;">/*
1、包最好采用小写字母
2、包的命名应该有规则,不能重复,一般采用公司网站逆序,
如:com.bjpowernode.项目名称.模块名称
com.bjpowernode.exam
 */
//package 必须放到所有语句的第一行,注释除外
package com.bjpowernode.exam;

public class PackageTest01 {
	public static void main(String[] args) {
		System.out.println("Hello Package!!!");
	}
}</span>

运行出现类不能找到错误,提示给的很明显,如com.bjpowernode.exam.PackageTest01 类不能找到,因为我们加入了包,所以我们的class 文件必须放到和包一样的目录里才可以,这就是采用包来管理类,也就是采用目录来管理类,建立目录com/bjpowernode/exam,采用javaPackageTest01 执行,同样出现上面的错误,如果采用了包在执行该类时必须加入完整的包名称,正确的执行方式为java com.bjpowernode.exam.PackageTest01正确执行通过。另外还有一点需要注意:必须在最外层包采用java 来执行,也就是classpath 必须设置在chapter03 目录上,以chapter03 目录为起点开始找我们的class 文件

2、import

如何使用包下的class 文件?

<span style="font-size:18px;color:#666666;">package com.bjpowernode.exam;

//采用import 引入需要使用的类
//import com.bjpowernode.exam.model.User;
//import com.bjpowernode.exam.model.Student;
//import com.bjpowernode.exam.model.Employee;
//可以采用* 通配符引入包下的所有类
//此种方式不明确,但简单
import com.bjpowernode.exam.model.*;
//package 必须放到所有语句的第一行,注释除外
//package com.bjpowernode.exam;

public class PackageTest02 {
	public static void main(String[] args) {
		User user = new User();
		user.setUserId(10000);
		user.setUserName("张三");
		System.out.println("user.id=" + user.getUserId());
		System.out.println("user.name=" + user.getUserName());
	}
}</span>

如果都在同一个包下就不需要import 引入了,以上的示例都没有包,可以理解为都在同一

个包下,在实际开发过程中不应该这样做,必须建立包

 


四、内部类

1、内部类的含义

在一个类的内部定义的类,称为内部类,内部类主要分类:实例内部类、局部内部类、静态内部类。

2、实例内部类

创建实例内部类,外部类的实例必须已经创建

实例内部类会持有外部类的引用

实例内部不能定义static 成员,只能定义实例成员

<span style="font-size:18px;color:#666666;">public class InnerClassTest01 {
	private int a;
	private int b;

	InnerClassTest01(int a, int b) {
		this.a = a;
		this.b = b;
	}

	// 内部类可以使用private 和protected 修饰
	private class Inner1 {
		int i1 = 0;
		int i2 = 1;
		int i3 = a;
		int i4 = b;
		// 实例内部类不能采用static 声明
		// static int i5 = 20;
	}

	public static void main(String[] args) {
		InnerClassTest01.Inner1 inner1 = new InnerClassTest01(100, 200).new Inner1();
		System.out.println(inner1.i1);
		System.out.println(inner1.i2);
		System.out.println(inner1.i3);
		System.out.println(inner1.i4);
	}
}</span>

3、静态内部类

静态内部类不会持有外部的类的引用,创建时可以不用创建外部类

静态内部类可以访问外部的静态变量,如果访问外部类的成员变量必须通过外部类的实例访问

<span style="font-size:18px;color:#666666;">public class InnerClassTest02 {
	static int a = 200;
	int b = 300;

	static class Inner2 {
		// 在静态内部类中可以定义实例变量
		int i1 = 10;
		int i2 = 20;
		// 可以定义静态变量
		static int i3 = 100;
		// 可以直接使用外部类的静态变量
		static int i4 = a;
		// 不能直接引用外部类的实例变量
		// int i5 = b;
		// 采用外部类的引用可以取得成员变量的值
		int i5 = new InnerClassTest02().b;
	}

	public static void main(String[] args) {
		InnerClassTest02.Inner2 inner = new InnerClassTest02.Inner2();
		System.out.println(inner.i1);
	}
}</span>

4、局部内部类

局部内部类是在方法中定义的,它只能在当前方法中使用。和局部变量的作用一样局部内部类和实例内部类一致,不能包含静态成员

<span style="font-size:18px;color:#666666;">public class InnerClassTest03 {
	private int a = 100;

	// 局部变量,在内部类中使用必须采用final 修饰
	public void method1(final int temp) {
		class Inner3 {
			int i1 = 10;
			// 可以访问外部类的成员变量
			int i2 = a;
			int i3 = temp;
		}
		// 使用内部类
		Inner3 inner3 = new Inner3();
		System.out.println(inner3.i1);
		System.out.println(inner3.i3);
	}

	public static void main(String[] args) {
		InnerClassTest03 innerClassTest03 = new InnerClassTest03();
		innerClassTest03.method1(300);
	}
}</span>

5、匿名内部类

匿名内部类是一种特殊的内部类,该类没有名字

<span style="font-size:18px;color:#666666;">//没有使用匿名类的情况
public class InnerClassTest04 {
	public static void main(String[] args) {
		MyInterface myInterface = new MyInterfaceImpl();
		myInterface.add();
	}
}
interface MyInterface {
	public void add();
}
class MyInterfaceImpl implements MyInterface {
	public void add() {
System.out.println("-------add------");
}</span>
<span style="font-size:18px;color:#666666;">//使用匿名类的情况
public class InnerClassTest05 {
	public static void main(String[] args) {
		/*
		 * MyInterface myInterface = new MyInterface() { public void add() {
		 * System.out.println("-------add------"); } }; myInterface.add();
		 */
		/*
		 * MyInterface myInterface = new MyInterfaceImpl(); InnerClassTest05
		 * innerClassTest05 = new InnerClassTest05();
		 * innerClassTest05.method1(myInterface);
		 */
		InnerClassTest05 innerClassTest05 = new InnerClassTest05();
		innerClassTest05.method1(new MyInterface() {
			public void add() {
				System.out.println("-------add------");
			}
		});
	}

	private void method1(MyInterface myInterface) {
		myInterface.add();
	}
}

interface MyInterface {
	public void add();
}
/*
 * class MyInterfaceImpl implements MyInterface { public void add() {
 * System.out.println("-------add------"); } }
 */</span>



五、参数传递与返回值

1、 接口名作为返回值类型

<span style="font-size:18px;color:#666666;">/*
   接口名作为返回值类型
       返回的是该接口的实现类的对象
*/
interface Love{
	public abstract void love();
}
//接口的实现类
class Teacher implements Love{
    public void love(){
	    System.out.println("爱学生,爱java,爱生活");
	}
}
class LoveDemo{
    
	public Love method(){
       //返回的时候你要找Love类型的对象 Love是一个接口 他不能直接创建对象
	   //所以你需要找他的实现类对象(接口多态)
	   return new Teacher();
	}

}
class ReturnDemo3{
	public static void main(String[] args) {
		//因为接口不能直接创建对象 要通过多态去实现
        LoveDemo ld = new LoveDemo();
		Love l= ld.method();//Love l = new Teacher();
		l.love();


	}
}
</span>

2、抽象类名作为返回值类型

<span style="font-size:18px;color:#666666;">/*
  抽象类名做为返回值类型
        返回的是该类子类对象

*/
abstract class Animal{
	public abstract void eat();
}
class Cat extends Animal{
	public void eat(){
	    System.out.println("猫吃鱼!");
	}
}
class AnimalDemo{
	public Animal method(){
	    //要return一个对象  什么类型的对象  Animal类型的 
		//  问:Animal是抽象类,不能直接创建对象
		// 他的子类对象,是不是Animal类型的对象  是  因为继承 
		//返回该类的子类对象
		return new Cat();
	}
}
class ReturnDemo2 {
	public static void main(String[] args) {
		//通过AnimalDemo 调用eat()方法
		AnimalDemo ad = new AnimalDemo();
        Animal a = ad.method();
		a.eat();

	}
}
</span>

3、类名作为返回值类型

<span style="font-size:18px;color:#666666;">/*
  类名作为返回值类型
      返回的是该类对象
    
*/
class Student{
	public void show(){
	  System.out.println("好好学习,天天向上");
	}
}
class StudentDemo{
    
	public Student method(){
	    return new Student(); 
	}
}
class ReturnDemo {
	public static void main(String[] args) {
		//怎么用
		StudentDemo sd = new StudentDemo();
		Student s = sd.method();
		s.show();
	}
}
</span>

4、链式编程

<span style="font-size:18px;color:#666666;">/*
  sd.method().show();  链式编程

  前提: 最后调方法的返回值要是一个类或者对象才可以
        每次调用完毕后返回的是一个对象

*/
class Student{
	public void show(){
	  System.out.println("好好学习,天天向上");
	}
}
class StudentDemo{
    
	public Student method(){
	    return new Student(); 
	}
}
class LinkedDemo {
	public static void main(String[] args) {
		//怎么用
		StudentDemo sd = new StudentDemo();
		Student s = sd.method();
		s.show();

		//简化写一下调用
        //改进一
		sd.method().show();

		//在简化
        new StudentDemo().method().show();
	}
}
</span>


















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值