多态与泛型
2016-04-01 15:52
281 查看
多态与泛型
1.多态的理解和使用:
多态自我理解就是同种调用的不同结果表现
1) 方法的多态性:包括重载和重写(其实重写就是为了下面类之间继承的多态)
2)类之间继承的多态
重载和重写已经在之前的文章中学习过了,下面是类的多态:
2.向上转型和向下转型
上述的类多态性使用实际上用到了向上转型;下面是向上转型和向下转型的使用:
如果中间的注释去掉的话,就会出现运行时异常,animal2是不能强转为cat类型的,下面是运行结果:
关于转型的自我理解:每个父类或者子类,都是一个指向引用的引用(暂定引用1),其中的方法是引用(暂定子引用2)。 当向上转型的时候,实际上就是子类的引用1和引用2
把父类的引用1和引用2都覆盖了,而且不存在丢失引用2的情况;当直接向下转型的时候,同样是覆盖,但是子类中可能会丢失引用2,所以java语法上不允许。 如果是先向上转型(不丢失引用2,同时多余的引用2仍然是存在的),再向下转型是可以的。
3.Java中instanceof使用
4.泛型
1)为什么要使用泛型
A:类型安全
B:不需要再使用强制类型转换,同时潜在的提高了效率。
如上A中所示,在利用泛型之后,不需要再使用强制类型转换,类型的判断有编译器来决定。 既然不需要强制类型转换,在编译的时候也就不需要类型转换占用的那些多余的字节码,这样会带来JVM的优化。
2)类中使用泛型
4)接口中使用泛型,数组中使用泛型
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); } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树