您的位置:首页 > 编程语言 > Java开发

多态与泛型

2016-04-01 15:52 281 查看
多态与泛型
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 泛型 多态