首页 > 试题广场 >

以下代码执行的结果是多少()?

[单选题]
以下代码执行的结果是多少()?
		public class Demo {
	public static void main(String[] args) {
		Collection<?>[] collections = 
{new HashSet<String>(), new ArrayList<String>(), new HashMap<String, String>().values()};
				Super subToSuper = new Sub();
				for(Collection<?> collection: collections) {
	System.out.println(subToSuper.getType(collection));
}
}
abstract static class Super {
	public static String getType(Collection<?> collection) {
		return “Super:collection”;
}
public static String getType(List<?> list) {
		return “Super:list”;
}
public String getType(ArrayList<?> list) {
		return “Super:arrayList”;
}
public static String getType(Set<?> set) {
		return “Super:set”;
}
public String getType(HashSet<?> set) {
		return “Super:hashSet”;
}
}
static class Sub extends Super {
	public static String getType(Collection<?> collection) {
            return "Sub"; }
}
}

  • Sub:collection
    Sub:collection
    Sub:collection
  • Sub:hashSet
    Sub:arrayList
    Sub:collection
  • Super:collection
    Super:collection
    Super:collection
  • Super:hashSet
    Super:arrayList
    Super:collection
这是静态分派的过程,在编译时已经决定了使用super的方法,因为subToSuper 是指super对象,可是为什么会选择collection呢,for循环出来他们实际上指的是collection对象表示的,即类似于Collection    col = new  HashSet<>();这样传入方法getType()中的参数就是col,左边是静态类型,右边是实际类型。由于重载实际上是使用静态分派的,重载时是通过参数的静态类型而不是实际类型作为判定依据的。详细参考深入理解java虚拟机248页解释。
编辑于 2017-08-18 22:59:39 回复(18)
考察点1:重载静态多分派——根据传入重载方法的参数类型,选择更加合适的一个重载方法
考察点2:static方法不能被子类覆写,在子类中定义了和父类完全相同的static方法,则父类的static方法被隐藏,Son.staticmethod()或new Son().staticmethod()都是调用的子类的static方法,如果是Father.staticmethod()或者Father f = new Son(); f.staticmethod()调用的都是父类的static方法。
考察点3:此题如果都不是static方法,则最终的结果是A. 调用子类的getType,输出collection
发表于 2017-08-30 09:05:30 回复(23)
***这个题这么老长,怎么读!
发表于 2018-07-11 09:27:45 回复(33)
public class A { 
    public static String staticStr = "A's static field";  
    public String nonStaticStr = "A's nonstatic field";  
    public static void staticMethod(){  
        System.out.println("A's static method");  
    }  
    public void nonStaticMethod(){  
        System.out.println("A's nonstatic method");  
    }  
}  
public class B extends A{
    public static String staticStr = "B's static field";  
    public String nonStaticStr = "B's nonstatic field";  
    public static void staticMethod(){  
        System.out.println("B's static method");  
    }  
}
public class C extends A{
  
} 
public class Test {  
  
    public static void main(String[] args) {  
        C c = new C();  
        System.out.println(c.nonStaticStr);  //A's nonstatic field
        System.out.println(c.staticStr);  //A's static field
        c.staticMethod(); //A's static method
       
        System.out.println("-------------------------------");  
          
        A c1 = new C();  
        System.out.println(c1.nonStaticStr);  //A's nonstatic field
        System.out.println(c1.staticStr);  //A's static field
        c1.staticMethod(); //A's static method
         
		// 以上这说明java中静态属性和静态方法可以被继承
        
		System.out.println("-------------------------------");  
        B b = new B();  
        System.out.println(b.nonStaticStr); // B's nonstatic field
        System.out.println(b.staticStr);   //B's static field
        b.staticMethod();  //B's static method
		
        System.out.println("-------------------------------");  
        A b1 = new B();  
        System.out.println(b1.nonStaticStr);  //A's nonstatic field
        System.out.println(b1.staticStr);  //A's static field
        b1.staticMethod(); //A's static method
		//b1.nonStaticStr  输出的是父类的非静态属性,说明非静态属性不可以被重写,不能实现多态
		//b1.staticStr     输出的是父类的静态属性,说明静态属性不可以被重写,不能实现多态
		//b1.staticMethod()输出的是父类A的静态方法,不是子类B改写后的,所以没有实现多态
		
		
	    //结论是:静态属性和静态方法只是可以继承没有表现出多态性。
		//因为静态方法和静态属性没有采用动态绑定。具体表现就是,
		//将子类实例向上转型则会调用到基类中的静态方法和属性,
		//不转型就调用子类自身的静态方法和属性。
		//编译器不推荐通过实例去调用静态方法和属性,因为这种调用方式容易造成混淆。
		
		//实际上,在Java的规范中,Java对于类的方法和属性采用了两种完全不同的处理机制:
		//对于方法,使用重载机制实现了多态性;对于属性,使用的是同名属性隐藏机制。
		//所谓的同名属性隐藏机制是指:在具有父子关系的两个类中,
		//子类中相同名字的属性会使得从父类中继承过来的同名属性变得不可见,
		//不管类型是否一致,名称一致的两个属性就是同名属性。
		//在子类中,无法简单地通过属性名称来获取父类中的属性,
		//而是必须通过父类名称加属性名称(super.变量名)的方法才可以访问父类中的该属性。
		//一般而言,为了代码容易阅读,极其不建议在父类和子类中使用同名属性。
    }  
  
}

编辑于 2017-08-29 10:32:34 回复(12)
选C
我觉得这个题没理解的好好去看看深入理解JVM虚拟机这本书的第八章的内容。
考了两个知识点:
    1. 静态方法,不存在重写,重写只对可见的实例方法有效。静态方法只有隐藏。
    2. 重载是根据形参的静态类型确定调用的方法版本,重写是根据调用者在运行期的实际类型来确定调用的方法版本。

public class Demo {
    public static void main(String[] args) {
        Collection<?>[] collections = // 注意, collections数组的静态类型是Collection的。
            { new HashSet<String>(),new ArrayList<String>(),new HashMap<String, String>().values()};//map.values()方法的返回值是Collection
       Super subToSuper = new Sub();//静态类型是Super,实际类型是Sub
    for(Collection<?> collection: collections) {
        System.out.println(subToSuper.getType(collection));//静态方法不存在重写,这里调用的是父类的getType方法,父类中有很多重载,根据数组的静态类型,确定调用版本
        }
}

发表于 2018-07-10 16:03:02 回复(5)
这题考察父类静态方法不能被子类重写,而是被隐藏!该题并未发生子类重写父类的getType()方法,只是父类有重载getType()行为,子类只是能继承父类的静态方法
发表于 2017-08-21 18:02:43 回复(0)

1、简单而言就是,静态方法不能被重写!
Father father = new Son(),
father调用静态方法时会是father中的方法。
类似java中的同名属性,但属性是会覆盖掉父类的。
2、我本来想选D的,不知道怎么点到C了~

答案是C,因为一开始定义数组的时候就是使用了Collection<?>[] collections,里面的数组元素会变成Collection类型!所以输出都是Super:collection,而不是Super:hashSet(一开始需要显式getType(new HashSet))!

public class Father {
    static int hello = 1;
    public static void  show(){
        System.out.println("这是父类的show");
    }
    public void method() {
        System.out.println("这是父类的method");
    }
}
public class Sub extends Father{
    static int hello = 2;
    public static void show() {
        System.out.println("这是子类的show");
    }
    public void  method() {
        System.out.println("这是子类的method");
    }
    public static void main(String[] args) {
        Father father = new Sub();
        Sub sub = new Sub();
        father.show(); 
        father.method();
        System.out.println("Sub.main()" + hello);
    }
}
/*
这是父类的show
这是子类的method
Sub.main()2
*/
编辑于 2017-12-03 10:52:50 回复(3)
此题可以和重载、重写;静态分派、动态分配联系起来。
简单的说,重载归属静态分派,在编译的时候编译器已经要确定调用的是哪个方法,所以是看参数的声明类型,也叫静态类型(即赋值号左边);而动态分配是在运行的时候才能确定,会先去声明类型的类中找到是否存在这个方法啊,然后再根据动态方法链从实际类型开始找到并调用最后重写该方法的那个最新的方法。

先来看下方法重载(Overloading)的定义:如果有两个方法的方法名相同,但参数不一致,哪么可以说一个方法是另一个方法的重载。 具体说明如下:
  • 方法名相同
  • 方法的参数类型,参数个不一样
  • 方法的返回类型可以不相同
  • 方法的修饰符可以不相同
  • main 方法也可以被重载
根据定义可知,此题Super中的方法均为重载,调用时即采取静态分派的措施,所以具体怎么调用看声明类型。

解题思路:
        由于静态方法没有重写一说,所以也就没有动态链的实现,而是被隐藏,要调用的话只能通过父类名.方法名,题目中是用的subTosuper(父类)   调用的getType方法,所以调用的则是Super类中的方法,又因为是静态分配,编译器会根据声明类型Collection去找到合适的方法调用,所以会三次调用Super类中的public static String getType(Collection<?> collection)方法,故选C

        如果Super和Sub都把public static String getType(Collection<?> collection)改为动态方法,则会先根据静态分派选择调用Super类的getType(Collection<?> collection)方法,然后再根据动态方法链选择这个方法的实现是Sub类中对该方法的重写,所以结果是:

编辑于 2018-07-27 12:00:06 回复(1)
手机上看到这种直接屏蔽!!!
发表于 2018-03-06 20:59:07 回复(2)
说实话看不太懂评论,我研读评论之后通俗地说应该是: 1.本题superToSub的方法是静态的,静态没有重写之说,所以本题并不是重写 2.依据编译看左运行看右知道,题目在编译时就是Super了,所以结果就是Super 请指正
发表于 2018-05-09 20:27:04 回复(0)
重载,[静态分配]: 参数匹配看实参定义(等号)的左边。 所以本题都是调用collection。 重写,[动态分派]: 调用谁的方法,看对象定义的右边。 然而本题是静态方法,并不是重写,而是属于子类独有的静态方法,又因为是向上转型,所以这时候只能访问父类与子类共有的属性,所以此时调用的是父类的方法。
编辑于 2017-12-23 00:35:00 回复(0)
手机上看这题,真要命.
发表于 2022-03-16 14:42:26 回复(0)
考了两个知识点: 1. 静态方法,不存在重写,重写只对可见的实例方法有效。静态方法只有隐藏。 2. 重载是根据形参的静态类型确定调用的方法版本,重写是根据调用者在运行期的实际类型来确定调用的方法版本。
发表于 2018-12-16 15:33:18 回复(0)
在继承中 静态属性和方法不能被重写,只能被继承,在调用的过程中,是通过静态绑定的,静态成员的调用依据的是对象的静态类型
如Super s = new Sub(); s则会调用父类的静态方法,因为其静态类型是Super(父类)。
另一方面,重载方法的调用也是静态绑定的,在编译期间通过方法的参数列表来判断应该调用哪一个方法,此时,由于是编译期间,那么理所当然 参照的参数类型也应该是静态类型。
因此最后 调用的是父类的静态方法,并且因为输入参数的静态类型已经被定死了,也就是 collection,所以最后都是调用 getType(Collection<?> collection) 这个方法

发表于 2018-02-01 19:36:16 回复(0)
首先要明确的是 Java 的多态有俩种,一个是基于重载的静态分派,一个是基于覆写(重写)的动态分派。其实语言类的分派一共四种,静态单分派,静态多分派,动态单分派,动态多分派,而 Java 是一种静态多分派动态单分派语言。

这里的静态单分派就是指的方法的重载了,动态单分派指的是覆写。其实他俩除了语法上的区别最重要的就是一个是编译器绑定,一个是运行期绑定,Jdk 1.7 之后的动态语言支持更充分利用了动态分派这一机制。

静态单分派就和上面的那位同学说的一样,Animal animal = new Cat() 中 animal 成为静态类型,即编译器可知的,而被 new 出来的 Cat 实例则成为实际类型,是运行期绑定的行为实例。和 C++ 一样,无论是虚函数或者纯虚函数,还是 Java 的抽象函数,或者虚方法,虚值的就是在编译期不可知的行为,并不是确切的。Java 除了 static 方法(invokestatic 指令调用),私有方法,构造方法,类方法(invokespecial)外其他的所有方法被成为虚方法(invokevirtual),而多态的机制就是建立在虚方法的基础上的。

实际上从 Java 反编译后的代码来看,类级别的 Java 的多态就是在各个父子类之间匹配查找的过程。所以单根继承 Object 使其方便管理,更易追溯源头,当然也不只这么点原因。

综上所述,Java 对于多态首先要明确的是,它只作用于方法之上,所有的 Field 都保留独有的特性;其次,对于 static,private,final 修饰的方法,同样不保留多态的行为。

多态是面向对象语言的特征之一,它的好处不言而喻,但实际上也是由于它的绑定机制,可能会出现在子类还没有初始化的时候由于类加载的双亲委派会先初始化父类,那此时可能就存在由于子类覆写父类方法,实际执行的是子类的方法导致出现意外的初值。
发表于 2017-11-13 09:59:30 回复(0)
这样的代码格式,分分钟想干掉写代码的人
发表于 2018-08-25 19:11:24 回复(0)
  • 静态方法(static修饰)是静态绑定,编译期间根据创建对象时,等号左边的数据类型确定调用父类还是子类的方法。因此不会调用子类Sub的`getType`方法,只会调用父类Super的。
  • 重载是静态绑定,编译时多态,编译期间根据实参的等号左边的数据类型去严格匹配形参的数据类型和个数。
public class StaticInherit {
    public static void main(String[] args) {
        Collection<?>[] collections =
                {new HashSet<String>(), new ArrayList<String>(), new HashMap<String, String>().values()};
        System.out.println("静态绑定,看编译类型(左边)");

        System.out.println("----------> 通过对象调用方法 <--------------");
        System.out.println("左边为父类,调用父类");
        Super subToSuper = new Sub();
        for(Collection<?> collection: collections) {
            System.out.println(subToSuper.getType(collection));
        }

        System.out.println("-------------------------");
        System.out.println("左边为子类,调用子类");
        Sub sub = new Sub();
        for(Collection<?> collection: collections){
            System.out.println(sub.getType(collection));
        }

        System.out.println("----------> 通过类调用方法 <--------------");
        System.out.println("Super调用方法");
        for(Collection<?> collection: collections){
            System.out.println(Super.getType(collection));
        }
        System.out.println("---------------------");
        System.out.println("Sub调用方法");
        for(Collection<?> collection: collections){
            System.out.println(Sub.getType(collection));
        }

        System.out.println("------------> 通过对象调用属性 <-------------");
        System.out.println(subToSuper.name);
        System.out.println(sub.name);
        System.out.println("------------> 通过类调用属性 <-------------");
        System.out.println(Super.name);
        System.out.println(Sub.name);
    }

    abstract static class Super {
        static String name = "Super";

        public static String getType(Collection<?> collection) {
            return "Super:collection";
        }
        public static String getType(List<?> list) {
            return "Super:list";
        }
        public String getType(ArrayList<?> list) {
            return "Super:arrayList";
        }
        public static String getType(Set<?> set) {
            return "Super:set";
        }
        public String getType(HashSet<?> set) {
            return "Super:hashSet";
        }
    }

    static class Sub extends Super {
        static String name = "Sub";

        public static String getType(Collection<?> collection) {
            return "Sub"; }
    }
}
  • 输出结果
静态绑定,看编译类型(左边)
----------> 通过对象调用方法 <--------------
左边为父类,调用父类
Super:collection
Super:collection
Super:collection
-------------------------
左边为子类,调用子类
Sub
Sub
Sub
----------> 通过类调用方法 <--------------
Super调用方法
Super:collection
Super:collection
Super:collection
---------------------
Sub调用方法
Sub
Sub
Sub
------------> 通过对象调用属性 <-------------
Super
Sub
------------> 通过类调用属性 <-------------
Super
Sub
编辑于 2022-04-15 21:00:58 回复(0)

1、简单而言就是,静态方法不能被重写!

因为一开始定义数组的时候就是使用了Collection<?>[] collections,里面的数组元素会变成Collection类型!所以输出都是Super:collection
2、静态函数,多态,编译和运行都看左边。
Father father = new Son(),
father调用静态方法时会是father中的方法。
类似java中的同名属性,但属性是会覆盖掉父类的。


发表于 2023-09-07 10:01:26 回复(0)
就不能把代码格式调规范吗,看着真难受
发表于 2022-03-15 20:58:55 回复(0)
java中静态属性和静态方法可以被继承,静态属性不可以被重写,不能实现多态。
发表于 2017-12-21 23:13:15 回复(0)