Java 为什么在实例化对象时需要列出两种对象类型?

Java 为什么在实例化对象时需要列出两种对象类型?,java,object,Java,Object,如果我把JungleCat作为Cat的一个子类(JungleCat扩展了Cat),然后我说: JungleCat cat1 = new JungleCat(); Cat cat2 = new Cat(); Cat cat3 = new JungleCat(); JungleCat cat4 = new Cat(); //this one is illegal, right? JungleCat cat5; 我想知道cat1、cat2、cat3、cat4和cat5的对象类型是什么?我还想知道为什

如果我把JungleCat作为Cat的一个子类(JungleCat扩展了Cat),然后我说:

JungleCat cat1 = new JungleCat();
Cat cat2 = new Cat();
Cat cat3 = new JungleCat();
JungleCat cat4 = new Cat(); //this one is illegal, right?
JungleCat cat5;
我想知道
cat1
cat2
cat3
cat4
cat5
的对象类型是什么?我还想知道为什么在实例化一个对象时会有冗余:为什么在实例化一个对象时需要列出两种对象类型


如果这是一个非常基本的问题,我很抱歉,但我只想一劳永逸地知道这类事情,并且有一个好的答案和好的推理,我知道我可以在这里期待(而不是Yahoo Answers等):p

当你实例化一个对象时,你必须指定

  • 新变量能够引用的引用类型或类型(类)是什么
  • 要初始化对象,我们需要指定对象的类型(类)
  • 所以基本上你需要创建一个JungleCat对象,同时创建一个指向它的引用。在以下情况下,指向它的参考能够指向猫(JungleCat、PetCat和所有猫)

    Cat cat3=新JungleCat()

    只有当

    JungleCat cat3=新JungleCat()

    关于

    cat1、cat2、cat3、cat4和cat5的对象类型?

    对象类型将是您从赋值运算符右侧向其赋值的对象

    关于

    JungleCat cat4=新的Cat()//这是非法的,对吗?

    是的,因为猫不一定是丛林猫(我们唯一知道的是,它是一只猫),但丛林猫肯定是一只猫。这就是为什么
    Cat=new JungleCat()是有效的

    JungleCat cat4=新Cat()//这个是非法的,对吗

    对。派生类引用不能指向其基类

    我想知道cat1、cat2、cat3、cat4和cat5的对象类型是什么

    用方法去了解

    为什么在实例化对象时需要列出两种对象类型


    这就是所谓的。i、 e.一个基类引用可以指向它的任何派生类。

    -
    多态性
    工作,因为子类对象被分配给超类对象引用变量

    -由于这是一个
    类多态性
    子类必须位于同一继承树中,并且子类必须是超类型的。

    So

    Cat c = new JungleCat();   // Will work
    
    但是,

    JungleCat c = new Cat();   // Won't work
    

    在以下声明中:-

    JungleCat cat1 = new JungleCat();
    
    Cat cat = new JungleCat();
    
    您可以将其分为两部分:-

    JungleCat cat1;  // This creates a reference of type `JungleCat`
    cat1 = new JungleCat();   // This creates an object of type `JungleCat`.
    
    现在,您正在创建
    cat1
    引用,指向
    JungleCat
    对象。引用只是指向所创建对象的链接,以便您可以访问它们

    您也可以像这样创建对象:-

    new JungleCat();   // Will create an unnamed object
    
    但是,在上述情况下,您将只能在实例化的位置使用方法和属性。但是,稍后,由于您没有访问该对象的引用,因此也无法访问其属性


    现在,让我们进入第二句话:-

    JungleCat cat1 = new JungleCat();
    
    Cat cat = new JungleCat();
    
    在这里,正如您所猜测的,您有类型为
    Cat-Super-Class
    的引用和类型为
    JungleCat
    的对象。这就是我们所说的多态性

    因此,基本上,您可以创建任何超级类型的引用,并使其指向任何子类型的对象。这很容易理解——“因为JungleCat只是一只猫。所以,你总是可以有一只猫作为JungleCat的参考点”

    反过来说,情况并非如此。例如:-

    JungleCat ref = new Cat();
    
    现在这是无效的。因为
    Cat
    不一定是
    JungleCat
    。它可以是任何其他的猫。因此,不能将
    JungleCat
    参考点指向
    Cat
    对象


    下面是您实际关心的问题:-

    我想知道cat1、cat2、cat3、cat4和cat4的对象类型是什么 第五类

    嗯,
    cat1
    cat2
    。。不是对象,而是指向某些对象的引用。从上面的解释中,你可以推断出它们的参考类型

    对象类型是在对象创建语句的RHS上使用的类型。与
    new
    关键字一起使用的类型是
    对象的类型。可以有不同类型的参照指向同一对象类型

    因此,您可以将
    cat1
    cat2
    引用都指向相同的对象类型

    cat1
    cat2
    cat3
    cat4
    cat5
    的对象类型是什么

    我不知道在这个上下文中“对象类型”是什么意思。我建议用声明类型和运行时类型来代替

    • cat1
      的声明类型为
      JungleCat
      cat1
      的运行时类型也是
      JungleCat
    • cat2
      的声明类型为
      Cat
      cat2
      的运行时类型也是
      Cat
    • cat3
      的声明类型为
      Cat
      cat3
      的运行时类型是
      JungleCat
    • cat4
      的声明类型为
      JungleCat
      cat4
      的运行时类型为
      Cat
      • 是的,这是违法的。如果没有明确的向下转换,它将无法编译;有明确的演员阵容。。。它可能会,但在运行时会抛出异常
    • cat5
      的声明类型为
      JungleCat
      ;它没有运行时类型
    “冗余”的意义在于Java是静态类型的,并且还支持动态调度。静态类型要求变量具有声明的类型;动态调度允许
    JungleCat jc1 = new JungleCat();
    Cat c1 = jc1;
    jc1.roar(); // compiles without error - JungleCats can roar!
    c1.roar(); // compile error! Cats don't roar
    
    public static void Claw(Cat cat)
    {
        cat.claw();
    }
    
    public class Cat
    {
        //...
    
        public void claw()
        {
            System.out.println("Cat claw");
        }
    }
    
    public class JungleCat extends Cat
    {
        //...
    
        @Override
        public void claw()
        {
            System.out.println("Jungle cat claw");
        } 
     }
    
    Cat c = new Cat();
    Cat j = new JungleCat();
    
    Claw(c); //Prints "Cat claw"
    Claw(j); //Prints "Jungle cat claw"
    
    public static void Claw(JungleCat junglecat)
    {
        junglecat.claw();
    }
    
    public interface FileMover
    {
        public void move(File f);
    }
    
    public class LinuxMover implements FileMover
    {
        public void move(File f)
        {
           //Move our file to /usr/bin
        }
    }
    
    public class WindowsMover implements FileMover
    {
        public void move(File f)
        {
           //Move our file to C:\Windows\System32
        }
     }
    
    //Pseudocode
    
    FileMover fm;
    if(OperatingSystem == LINUX) {
        fm = new LinuxMover();
    } 
    else if(OperatingSystem == WINDOWS) { 
        fm = new WindowsMover();
    }
    
    fm.move();