多态与泛型

本文探讨了Java中的多态性,包括方法的重载和重写,以及类之间的继承多态。着重讲解了向上转型和向下转型的概念,并通过示例解释了为什么在某些情况下会出现运行时异常。此外,还介绍了`instanceof`关键字的用途。最后,文章讨论了泛型的重要性,如类型安全和提高效率,并展示了如何在类、接口和数组中使用泛型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多态与泛型

1.多态的理解和使用:

多态自我理解就是同种调用的不同结果表现

1) 方法的多态性:包括重载和重写(其实重写就是为了下面类之间继承的多态)

2)类之间继承的多态

重载和重写已经在之前的文章中学习过了,下面是类的多态:

class animal{
	public void eat(){
		System.out.println("animal.eat()");
	}
}
class cat extends animal{
	public void eat(){
		System.out.println("cat.eat()");
	}
}
class dog extends animal{
	public void eat(){
		System.out.println("dog.eat()");
	}
}
public class abs{
	/*方法1*/
//	public static void toEat(cat cat){
//		cat.eat();
//	}
//	public static void toEat(dog dog){
//		dog.eat();
//	}
	/*方法2*/
	public static void toEat(animal animal){
		animal.eat();
	}
	public static void main(String[] args) {
		toEat(new cat());
		toEat(new dog());
	}
}
想调用cat和dog子类的eat方法,如果使用方法1的话,要用到两个静态方法,如果有很多子类的话这是不可行的;如果使用方法2的话,参数是父类,只需要用一个方法即可

2.向上转型和向下转型

上述的类多态性使用实际上用到了向上转型;下面是向上转型和向下转型的使用:

class animal{
	public void eat(){
		System.out.println("animal.eat()");
	}
	public void sleep(){
		System.out.println("animal.sleep()");
	}
}
class cat extends animal{
	public void eat(){
		System.out.println("cat.eat()");
	}
	public void breath(){
		System.out.println("cat.breath()");
	}
}
public class abs{
	public static void main(String[] args) {
		/*向上转型*/
		animal animal = new animal();
		cat cat = new cat();
		animal = cat;
		animal.eat();
		animal.sleep();
		System.out.println();
		
		/*向下转型,这种是错误的*/
//		animal animal2 = new animal();
//		cat cat2 = new cat();
//		cat2 = (cat)animal2;
//		System.out.println();
		
		/*向下转型*/
		animal animal3 = new cat();
		cat cat3 = new cat();
		cat3 = (cat)animal3;
		cat3.eat();
		cat3.sleep();
		cat3.breath();
	}
}
实际上向下转型,是子类先向上转型,然后再向下转型;下面是运行结果:


如果中间的注释去掉的话,就会出现运行时异常,animal2是不能强转为cat类型的,下面是运行结果:



关于转型的自我理解:每个父类或者子类,都是一个指向引用的引用(暂定引用1),其中的方法是引用(暂定子引用2)。 当向上转型的时候,实际上就是子类的引用1和引用2

把父类的引用1和引用2都覆盖了,而且不存在丢失引用2的情况;当直接向下转型的时候,同样是覆盖,但是子类中可能会丢失引用2,所以java语法上不允许。 如果是先向上转型(不丢失引用2,同时多余的引用2仍然是存在的),再向下转型是可以的。

3.Java中instanceof使用

class animal{
	public void eat(){
		System.out.println("animal.eat()");
	}
	public void sleep(){
		System.out.println("animal.sleep()");
	}
}
class cat extends animal{
	public void eat(){
		System.out.println("cat.eat()");
	}
	public void breath(){
		System.out.println("cat.breath()");
	}
}
public class abs{
	public static void main(String[] args) {
		animal Tanimal = new animal();
		cat Tcat = new cat();
		animal Fanimal = new cat();
//		((cat)Fanimal).breath();
		System.out.println(Tanimal instanceof cat);
		System.out.println(Tcat instanceof animal);
		System.out.println(Fanimal instanceof cat);
		System.out.println(Fanimal instanceof animal);
	}
}
注:即使实例通过了instanceof验证,表明是相关类的实例,也并不一定可以直接调用实例中的方法,如上段注释的代码,是需要强转的。下面是运行结果:

4.泛型

1)为什么要使用泛型

A:类型安全

		Map map = new HashMap();
		map.put("int", 10);
		String string = (String)map.get("int");
上面的代码,程序员可能会忘记map中”int“键存放的是int类型,在取出的时候会当作String类型,这在运行的时候会出现java.lang.ClassCastException异常。
		Map<String,Integer> map2 = new HashMap<>();
		map2.put("int",10);
		/*下面注释的写法就是错的*/
//		String string2 = (String)map2.get("int");
		int num = map2.get("int");
上面的代码利用泛型避免了出现异常的问题

B:不需要再使用强制类型转换,同时潜在的提高了效率。

如上A中所示,在利用泛型之后,不需要再使用强制类型转换,类型的判断有编译器来决定。  既然不需要强制类型转换,在编译的时候也就不需要类型转换占用的那些多余的字节码,这样会带来JVM的优化。

2)类中使用泛型

/*类中使用泛型*/
class animal<T,K,L>{
	/*属性中使用泛型*/
	private T name;
	private K age;
	private L print;
	/*构造方法中使用泛型*/
	public animal(L l){
		this.print = l;
		System.out.println("animal.animal():"+this.print);
	}
	public T getName() {
		return name;
	}
	public void setName(T name) {
		this.name = name;
	}
	public K getAge() {
		return age;
	}
	public void setAge(K age) {
		this.age = age;
	}
}
/*下面的注释,说明子类也必须是同样的类型*/
//class cat<T,K,L> extends animal<T,K,L>{
//	public cat(L l) {
//		super(l);
//	}
//}
public class abs{
	public static void main(String[] args) {
		animal<String,Integer,String> animal = new animal<String, Integer, String>("这是参数L初始化的值");
		animal.setName("tiger");
		animal.setAge(10);
		System.out.println("name:"+animal.getName());
		System.out.println("age:"+animal.getAge());
	}
}
3)泛型类作为方法参数时的,需要使用通配符的问题
/*类中使用泛型*/
class animal<T,K>{
	/*属性中使用泛型*/
	private T name;
	private K age;
	public T getName() {
		return name;
	}
	public void setName(T name) {
		this.name = name;
	}
	public K getAge() {
		return age;
	}
	public void setAge(K age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "animal [getName()=" + getName() + ", getAge()=" + getAge() + "]";
	}
	
}
/*下面的注释,说明子类也必须是同样的类型*/
//class cat<T,K,L> extends animal<T,K,L>{
//	public cat(L l) {
//		super(l);
//	}
//}
public class abs{
	public static void main(String[] args) {
		animal<String,Integer> animal = new animal<String,Integer>();
		animal.setAge(10);
		animal.setName("tiger");
		test(animal);
	}
	/*方法1*/
	public static void test(animal<?,?> animal){
		System.out.println("abs.test():"+animal.toString());
	}
	/*方法2*/
/*对于一个static的方法而言,无法访问泛型类的类型参数,所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。*/
//	public static<T, K> void test(animal<T,K> animal){
//		System.out.println("abs.test():"+animal.toString());
//	}
}
注:除了在方法中使用通配符之外,还可以使用上段代码中方法2.

4)接口中使用泛型,数组中使用泛型

interface plants<T,K,L>{
	/*泛型方法*/
	public T eat(T t,K k,L l[]); 
}
class tree<T,K,L> implements plants<T,K,L>{
	public T eat(T t,K k,L l[]) {
		System.out.println("tree.eat():"+t.toString());
		System.out.println("tree.eat():"+k.toString());
		for (int i = 0; i < l.length; i++) {
			System.out.println("tree.eat():"+l[i].toString());
		}
		return t;
	}
}
public class abs{
	public static void main(String[] args) {
		Integer integer[] = {1,2,3};
		tree<String,String,Integer> tree = new tree<String,String,Integer>();
		tree.eat("t值","k值",integer);
	}
}
5)对上面的代码做一点改动,在接口中去掉T泛型, 那么在使用其中的eat方法的时候就必须指定为泛型方法,即在返回值浅加上泛型。这样一个好处是不用在实例化的时候指定类型,只需要在调用方法的时候指定类型即可。
interface plants<K,L>{
	/*泛型方法*/
	public <T>T eat(T t,K k,L l[]); 
}
class tree<K,L> implements plants<K,L>{
	public <T>T eat(T t,K k,L l[]) {
		System.out.println("tree.eat():"+t.toString());
		System.out.println("tree.eat():"+k.toString());
		for (int i = 0; i < l.length; i++) {
			System.out.println("tree.eat():"+l[i].toString());
		}
		return t;
	}
}
public class abs{
	public static void main(String[] args) {
		Integer integer[] = {1,2,3};
		tree<String,Integer> tree = new tree<String,Integer>();
		tree.eat("t值","k值",integer);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值