简体   繁体   中英

Java. Type vs Object of a class

For example, when I have a class Rectangle, and a class Square. If class Square extends Rectangle, therefore class square is a subclass of class 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. So did I create an object of Square, but have type 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. The object will have type Square throughout its existence.

When you declare a variable with type Rectangle , ie Rectangle x; or 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 ). When you say Rectangle x = new Square(...) , x will be a reference to a Square , which is a Rectangle . However , x could later be reassigned to become some other Rectangle that isn't a Square .

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. If you declare a new method in Square , you can't use it with the above call.

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 ).

Maybe this example will help. Suppose that Rectangle declares public methods aaa and bbb . In Square , you write an overriding method aaa , you don't override bbb , and you declare a new public method 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.

A call to new Foo(...) will always create a Foo, no exceptions. And it'll always call the constructor for Foo , again without exceptions. That said, if Foo extends from another class, then the first thing Foo's constructor will do is to invoke the superclass's constructor. 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. 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. 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. 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.

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.

Inheritance always gives your objects an is-a relationship . So, by virtue of Square extending Rectangle , it's safe to say that a Square is-a 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.

What you are looking for is answer to question "Is Square really a rectangle?". 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 .

So essentially if base class has some methods which are not applicable for derived class then its not a "is-a" relationship.

eg

class Rectangle{

/ Constructor Code /

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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