简体   繁体   English

Java。 类的类型与对象

[英]Java. Type vs Object of a class

For example, when I have a class Rectangle, and a class Square. 例如,当我有一个Rectangle类和一个Square类时。 If class Square extends Rectangle, therefore class square is a subclass of class Rectangle. 如果Square类扩展Rectangle,则Square类是Rectangle类的子类。 Now say I had the code. 现在说我有代码。 Rectangle shape = new Square(5,6); I would be creating an object, but would it be type Rectangle, but using the constructor of square, or an object of Square?, my confusion starts with class Square has the same methods of class Rectangle, but it will use the methods in class Square not class Rectangle. 我将创建一个对象,但是它将是Rectangle类型,但是使用square的构造函数还是Square的对象?,我的困惑始于类Square,它具有与Rectangle类相同的方法,但是它将使用类中的方法方形不类矩形。 So did I create an object of Square, but have type Rectangle? 那么我是否创建了Square对象,但是具有Rectangle类型?

Comment: Everyone is getting angry knowing square does not extend rectangle, but this was my teachers example purely showing inheritance, infact at the end he was showing how if we use this code, it creates a bug. 评论:每个人都知道正方形不会扩展矩形,这让每个人都感到愤怒,但这是我的老师的例子,纯粹显示了继承性,实际上他在演示如何使用此代码如何创建错误。

This confuses a lot of people. 这使很多人感到困惑。 Let me try to break it down. 让我尝试将其分解。

When you say new Square , the object is created using the Square constructor. 当您说new Square ,将使用Square构造函数创建对象。 The object will have type Square throughout its existence. 该对象在其整个存在期间将具有Square类型。

When you declare a variable with type Rectangle , ie Rectangle x; 当声明类型为Rectangle的变量时,即Rectangle x; or Rectangle x = (anything); Rectangle x = (anything); you're telling the compiler that x (when it's not null) will always be a reference to Rectangle or any of its subclasses (including Square ). 您告诉编译器x (当它不为null时)将始终是对Rectangle 或其任何子类 (包括Square )的引用。 When you say Rectangle x = new Square(...) , x will be a reference to a Square , which is a Rectangle . 当您说Rectangle x = new Square(...)x将是对Square的引用,即Rectangle However , x could later be reassigned to become some other Rectangle that isn't a Square . 但是 ,以后可以将x重新分配为其他不是Square Rectangle

That means that, when you say x.method(...) , the compiler only allows you to use the methods that are defined in Rectangle , because the compiler only knows that x is a Rectangle or some subclass. 这意味着,当您说x.method(...) ,编译器仅允许您使用Rectangle中定义的方法,因为编译器仅知道xRectangle或某些子类。 If you declare a new method in Square , you can't use it with the above call. 如果在Square声明一个新方法,则不能在上面的调用中使用它。

However, if x still is a reference to a Square , then when you call a method defined in Rectangle , the program will actually run the method you wrote for Square (if you've overridden the one in Rectangle ). 但是,如果x仍然是对Square的引用,那么当您调用Rectangle定义的方法时,该程序实际上将运行您为Square编写的方法(如果已覆盖Rectangle )。

Maybe this example will help. 也许这个例子会有所帮助。 Suppose that Rectangle declares public methods aaa and bbb . 假设Rectangle声明了public方法aaabbb In Square , you write an overriding method aaa , you don't override bbb , and you declare a new public method ccc . Square ,您编写了重写方法aaa ,没有重写bbb ,而是声明了一个新的公共方法ccc

Rectangle x = new Square(10);
Rectangle y = new Rectangle(5,6);

// assume that x and y aren't changed 

x.aaa();   // runs the overriding method aaa in Square
y.aaa();   // runs the method aaa in Rectangle

x.bbb();   // runs the method in Rectangle, since it's not overridden.  But
           // if bbb calls aaa, then it will call the aaa in Square.
y.bbb();   // runs the method in Rectangle

x.ccc();   // illegal.  Even though the object is actually a Square, the
           // compiler isn't allowed to know that.
y.ccc();   // illegal

((Square)x).ccc();  // This is how you can get to the new method that you
           // declared in Square.  Even though the compiler doesn't know 
           // that x is a Square, when you use the cast, you tell the 
           // compiler that it's OK fo treat it as a Square, and to access
           // the method defined only in Square.
((Square)y).ccc();  // Will throw ClassCastException at runtime, because 
           // y isn't a Square.

Hope this helps. 希望这可以帮助。

You created an object of type Square. 您创建了一个Square类型的对象。

A call to new Foo(...) will always create a Foo, no exceptions. new Foo(...)调用将始终创建Foo,没有例外。 And it'll always call the constructor for Foo , again without exceptions. 而且它将始终再次调用Foo的构造函数,而不会出现异常。 That said, if Foo extends from another class, then the first thing Foo's constructor will do is to invoke the superclass's constructor. 也就是说,如果Foo从另一个类扩展,那么Foo的构造函数要做的第一件事就是调用超类的构造函数。 Again, there are no exceptions to this, ever — though you won't necessarily see it in the code, because if you don't have a call to super(...) and there exists a no-argument constructor in the super class, then the compiler will automatically invoke that constructor for you. 再说一次,这也没有例外-尽管您不一定会在代码中看到它,因为如果您没有对super(...)的调用,并且在super中存在无参数的构造函数类,则编译器将自动为您调用该构造函数。 But one way or the other, it'll always get invoked. 但是,无论哪种方式,它总是会被调用。

Since you've set it up that a Square is-a rectangle, that object is also an instance of Rectangle. 由于已将Square设置为一个矩形,因此该对象也是Rectangle的实例。 With your classes, a Square is always a Rectangle, but not all Rectangles are Squares. 在您的课程中,正方形始终是矩形,但并非所有矩形都是正方形。

The Rectangle shape bit just means that as far as the compiler knows, it's "at least" a Rectangle. Rectangle shape仅表示,据编译器所知,它“至少”是Rectangle。 It may be exactly a Rectangle, or it may be a subclass of Rectangle (like Square) -- but it won't be, for instance, a Number. 它可能完全是一个Rectangle,也可能是Rectangle的子类(例如Square),但不会是Number。

When you call shape.getArea() (for instance), the JVM will look up the actual type of shape — not just its compile-time type, but the type it was actually created as when you invoked new — and invoke the method that that class defines. 例如,当您调用shape.getArea() ,JVM将查找shape实际类型(不仅是其编译时类型,而且还包括您在调用new时实际创建的类型),并调用该方法。该类定义。

Inheritance always gives your objects an is-a relationship . 继承总是给您的对象一个is-a关系 So, by virtue of Square extending Rectangle , it's safe to say that a Square is-a Rectangle . 因此,凭借Square扩展的Rectangle ,可以肯定地说Square Rectangle

You have created an instance of Square , but you will only be able to use the methods provided by its parent Rectangle on it. 您已经创建了Square的实例,但是您将只能在其实例上使用其父Rectangle提供的方法。

What you are looking for is answer to question "Is Square really a rectangle?". 您在寻找的答案是“ Square真的是矩形吗?”。 From gemoetry perspective answer is yes but from software perspective answer may not be so obvious. 从宝石学的角度来看,答案是肯定的,但从软件的角度来看,答案可能并不那么明显。 "Is-a" relationship has to follow Liskov Substitution principle . “是”关系必须遵循Liskov替代原则

So essentially if base class has some methods which are not applicable for derived class then its not a "is-a" relationship. 因此,基本上,如果基类具有某些不适用于派生类的方法,则它不是“ is-a”关系。

eg 例如

class Rectangle{ 矩形类{

/ Constructor Code / / 构造函数代码 /

public void changeWidth(){....} public void changeLength(){....} public void changeWidth(){....} public void changeLength(){....}

} }

changeWidth and changeLength are two functions which make perfect sense for a rectangle but not for Square since all sides are equal in square. changeWidth和changeLength是两个函数,它们对于矩形(而不是正方形)非常有意义,因为所有边都相等。 Though you can hack and give your own implementation of both function in square class still from my point of view relationship does not look natural. 尽管从我的角度来看,尽管您可以在平方类中破解并给出自己的两个函数的实现,但是关系看起来并不自然。

As for other answers I do agree with them. 至于其他答案,我也同意。

That's called Polymorphism, do your homework. 那就是所谓的多态性,做功课。 the shape variable is only a reference but the real object is a Square object. shape变量仅是参考,而实际对象是Square对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM