黑马程序员-JAVA基础-多态、内部类、异常

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、多态

1.概念:某一事物的多种表现形态

2.程序的体现:

父类或接口的引用可以指向自己的子类对象
父类或接口的引用可以接受自己的子类对象

例如

/*
猫和狗都属于动物,是动物的两种不同表现形式
*/
abstract class Animal
{
	public abstract void eat();//吃东西为动物的共性方法,但是不明确吃什么,所以定义为抽象
}
class Cat extends Animal
{
	public void eat()
	{
		System.out.println("吃鱼");
	}
	public void catchMouse()//猫的特有功能
	{
		System.out.println("抓老鼠");
	}
}
class Dog extends Animal
{
	public void eat()
	{
		System.out.println("吃骨头");
	}
	public void kanJia()//狗的特有功能
	{
		System.out.println("看家");
	}
}
class DuoTaiDemo 
{
	public static void main(String[] args) 
	{
		Cat c = new Cat();
		c.eat();

		Animal a = new Dog();//可以通过父类引用指向子类对象
		a.eat();

		method(new Cat());//通过父类接收自己的子类对象
	}

	public static void method(Animal a)
	{
		a.eat();
	}
}
在上面的程序中,通过 Animal a = new Dog();  a不能访问Dog中的Kanjia()方法。要是父类的应用能访问子类的特有方法,这时就用到了类型转换

Dog d = (Dog)a;//向下转型
d.kanJia();
2.多态的前提:

类与类之间必须存在继承或实现;必须有覆盖操作

3.多态的好处和弊端:

好处:消除类型之间的耦合性

   改善代码的组织结构和可读性

   提高程序的扩展性

4.多态中成员的特点:

成员函数的特点:

编译时:参阅引用型变量所属的类中是否有调用方法,如果有就编译通过,否则反之。

运行时:参阅对象所属类中是否存在调用方法

成员变量的特点:

编译和运行,都参阅引用型变量所属类

静态成员函数的特点:同上

原因:被静态修饰的方法可以直接被类名调用,编译后,内存中会产生父类的class文件,运行时,会先找父类中的静态方法。

例:

class Fu
{
	int num = 4;
	void method_1()
	{
		System.out.println("fu--method_1");
	}
	void method_2()
	{
		System.out.println("fu--method_2");
	}
	static void method_4()
	{
		System.out.println("fu--method_4");
	}
}
class Zi extends Fu
{
	int num = 6;
	void method_1()
	{
		System.out.println("zi--method_1");
	}
	void method_3()
	{
		System.out.println("zi--method_3");
	}
	static void method_4()
	{
		System.out.println("zi--method_4");
	}
}
class DuoTaiDemo2 
{
	public static void main(String[] args) 
	{
		Fu f = new Zi();
		f.method_1();
		f.method_2();
		//f.method_3(); 编译失败,因为Fu类中没有method_3()这个方法
		System.out.println(f.num);//运行结果为4,
		f.method_4();//运行结果为fu--method_4
	}
}

5.多态的应用:

/*
电脑是基于主板运行的
*/
interface PIC//PCI插槽
{
	public void open();//打开方法
	public void close();//关闭方法
}
class NetCard implements PIC
{
	public void open()
	{
		System.out.println("netCard open");
	}
	public void close()
	{
		System.out.println("netCard close");
	}
}
class SoundCard implements PIC
{
	public void open()
	{
		System.out.println("SoundCard open");
	}
	public void close()
	{
		System.out.println("SoundCard open");
	}
}
class Mainboard//主板
{
	public void run()
	{
		System.out.println("Mainboard run");
	}

	public void usePIC(PIC p)//主板使用pci插槽
	{
		if(p!=null)
		{
			p.open();
			p.close();
		}
	}
}
class DuoTaiTest 
{
	public static void main(String[] args) 
	{
		Mainboard m = new Mainboard();
		m.run();//运行结果 Mainboard run
		m.usePIC(new NetCard());//netCard open
					//netCard close
	}
}

 二、内部类

1、访问规则:内部类可以直接访问外部类成员,包括私有。原因:内部类中带有一个外部类的引用,外部类名.this

     外部类要访问内部类,要建立内部类对象。

class Outer//外部类
{
	int num = 2;
	void method()
	{
		System.out.println("外部类:"+num);
		Inner in = new Inner();//外部类通过new内部类对象
		in.function();
	}

	class Inner//内部类
	{
		void function()
		{
			System.out.println("外部类:"+num);//内部类直接访问外部类成员变量num
		}
	}
}
class InnerClassDemo 
{
	public static void main(String[] args) 
	{
		Outer ou = new Outer();
		ou.method();
	}
}
2、访问格式

如果要直接访问内部类的function,可以通过下面的格式

Outer.Inner in = new Outer().new Inner();
in.function();

2.1非私有内部类可以在外部其他类中直接建立对象

外部类名.内部类名 变量名 = 外部类对象.内部类对象

2.2当内部类定义在外部类的成员位置上时,可以被private和static修饰

当内部类被static修饰时,便具有了静态的属性

2.3当内部类定义在外部类的局部位置时,也可以直接访问外部类的成员变量,但是访问外部类局部变量时,该变量要被final修饰。

3.匿名内部类:

3.1概念:内部类的简写格式,前提是内部类必须继承或实现接口

3.2好处:简化书写

3.3格式:new 父类或接口()

{

定义子类内容

}

3.4练习:

interface Inner
{
	void method();
}
class Test
{
	//补足代码
	static Inner function()
	{
		return new Inner()
		{
			public void method()
			{
				System.out.println("method run");
			}
		};
	}
}
class InnerClassTest 
{
	public static void main(String[] args) 
	{
		Test.function().method();//根据这句代码,在Test类中补足代码
		/*
		分析:Test.function()这句代码,说明Test类中有一个静态function方法
		function().method();说明function方法运行后是一个对象,而且是Inner对象,
		因为Inner对象里面才定义了method方法
		*/
	}
}
3.5问题:一个类没有继承或者实现接口,能不能写匿名内部类,并使用其方法

例如:

new Object()
{
	public void function()
	{
				
	}
			
}.function();

三、异常:

1、概念:就是程序运行中出项不正常的情况,java对其进行封装,并形成一个异常体系。

2、异常体系,通过查阅javaAPI帮助文档


Throwable类是所有异常类的父类

|——Error  严重问题,java没有编写针对性的代码进行处理

|——Exception  非严重问题,java编写了相应的代码进行处理

        |——RuntimeException Exception的子类,运行时异常

例如

class ExceptionDemo 
{
	public static void main(String[] args) 
	{
		int[] arr = new int[5];
		System.out.println(arr[6]);
	}
}
上面代码编译时没有问题,但运行时出现了角标越界异常,这种异常属于Exception,java虚拟机给出了对应的提示,并且将程序停止



3、异常的处理

try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;通常用于释放资源
}

例如

class Demo
{
	int div(int a,int b)
	{
		return a/b;
	}
}
class ExceptionDemo2 
{
	public static void main(String[] args) 
	{
		Demo d = new Demo();
		try
		{
			int x = d.div(4,0);
			System.out.println("结果是"+x);
		}
		catch (Exception e)//Exception e = new ArithmeticException(); 多态的体现
		{
			System.out.println("除数不能为0");
		}
		System.out.println("over");
	}
}
运行结果


4、对捕获到的异常进行常见方法操作


5、在编写功能时,如果可能会出现异常,要在功能上抛出异常,比如

class Demo
{
	int div(int a,int b)throws Exception//在有可能发生异常的方法进行标示
	{
		return a/b;
	}
}
class ExceptionDemo3
{
	public static void main(String[] args) 
	{
		Demo d = new Demo();
		int x = d.div(4,0);
		System.out.println("结果是"+x);
		System.out.println("over");
	}
}
编译时会发生如下提示


一旦方法声明了抛出异常,在使用该方法时,必须将编写代码处理异常,要么是try和catch,要么是再将其抛出


6、自定义异常:继承Exception类

例如:

class FuShuException extends Exception
{
	private int value;
	FuShuException()//空参数构造函数
	{
		super();
	}
	FuShuException(String msg,int value)//自定义异常信息的构造函数
	{
		super(msg);
		this.value = value;
	}
	public int getValue()
	{
		return value;
	}
}
class Demo
{
	int div(int a,int b)throws FuShuException
	{
		if(b<0)
			throw new FuShuException("除数不能为负数",b);
		return a/b;
	}
}
class ExceptionDemo4 
{
	public static void main(String[] args) 
	{
		Demo d = new Demo();
		try
		{
			int x = d.div(4,-1);
			System.out.println("结果是"+x);
		}
		catch (FuShuException e)
		{
			System.out.println(e.toString());
		}
	}
}
运行结果为:


在上面的程序中,对于除数为-1也定义为异常,所以需要自己自定义异常类

这里涉及到两个关键字:throws和throw,他们有什么区别呢?

throws 定义在函数上,后面跟异常类,可以声明多个,用逗号隔开
throw 定义在函数内,后面跟异常对象

7、RuntimeException(运行时异常)

如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。
如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过

为什么运行时异常不用在函数上进行声明呢?

不在函数上进行声明,调用方法时就不用进行处理,在运行时,发生该异常可以让程序停止,这时程序员就可以找到哪段代码出错

并且进行修正。这样就不会将问题隐藏。

在上面的程序中,自定义的负数异常应该继承RuntimeException更为合理。

8、异常在子父类中的特点

(1)、子类在覆盖父类方法时,如果父类抛出异常,那么子类覆盖的方法只能抛出父类的异常或者该异常的子类。

(2)、如果父类或接口没有抛出异常,那么子类也不能抛出异常,如果子类中有异常,只能进行try和catch处理。

9、练习

/*
需求:有圆和矩形,都能获取面积,但是对于矩形的宽高或者圆的半径作了规定,
必须大于0,否则就会发生异常
分析:圆和矩形都有获取面积的方法,那就可以抽取出来,可以定义一个接口,里面有获取面积的方法
但是怎么获取是不确定的。
当用户传入的值不合法时,会发生异常,这是就可以自定义异常,并且这个异常在编译时可以通过,
在运行时就会告诉用户,传入的值不合法,
*/
class LengthException extends RuntimeException//自定义异常,继承RuntimeException
{
	public LengthException(String msg)
	{
		super(msg);
	}
}
interface Area//定义接口,里面有获取面积的方法
{
	void getArea();
}
class MyRectangle implements Area//矩形类,
{
	private int width;//矩形的宽
	private int height;//矩形的高
	
	public MyRectangle(int width,int height)//具有宽和高的构造函数
	{
		if(width<=0 || height<=0)
			throw new LengthException("长或宽必须大于0");
		this.width = width;
		this.height = height;
	}
	public void getArea()//矩形获取面积的特有方法
	{
		System.out.println("矩形的面积为"+width*height);
	}
}
class Circle implements Area//圆形类
{
	private final double PI = 3.14;//π的值是固定的,可以声明为final类型
	private int radius;//圆的半径
	public Circle(int radius)//具有半径的构造函数
	{
		if(radius<=0)
			throw new LengthException("半径必须大于0");
		this.radius = radius;
	}
	public void getArea()//获取圆的面积的特有方法
	{
		System.out.println("圆的面积为"+radius*PI*PI);
	}
}
class ExceptionTest 
{
	public static void main(String[] args) 
	{
		MyRectangle rec = new MyRectangle(1,4);
		rec.getArea();
		
		Circle c = new Circle(2);
		c.getArea();
	}
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值