1

let me first explain what i want to say actually

Suppose a class Sub inheriting the class Super. now we can excess all no private members of class Super within class Sub. now Suppose the case

class Super{
    private int id;
    public int getId()
    {
        return id;
    }
}

class Sub extends Super {
    public static void main(String args[]){
        Sub sub = new Sub();
        System.out.println(sub.getId());
    }
}

I know that creating Sub class object will call Super class constructor too. But the job of constructor is to initialize the fields only -- not to allocate the memory to the object.

Moreover in case of abstract class where the initialization is not allowed we can still use the instance variable of abstract class.

The memory to instance variable will be assigned at time of instance creation only.

Than how can we use the instance fields without even creating the instance. Doesn't it violets the oops concept..??

Please help over this. And thanks in advance.

yshavit
  • 42,327
  • 7
  • 87
  • 124
sandiee
  • 153
  • 1
  • 8
  • 1
    All instances of `Sub` are also instances of `Super.` When you create an instance of `Sub` that object also has all the fields from `Super.` That's the definition of `extends` – Ian McLaird Mar 29 '15 at 04:50
  • 2
    "in case of abstract class where the initialization is not allowed" Wrong: fields in an abstract base class can be initialized, by assignment in the declaration or by the constructor. – laune Mar 29 '15 at 04:52
  • i think the private members of Super are not inheritable and cant be an instance field of Sub – sandiee Mar 29 '15 at 04:53
  • @laune i said that the class cant be instantiated. how can you you intiallize instance field of a class without instantiating it – sandiee Mar 29 '15 at 04:55
  • @sanidee, no. The private members are inherited and are still there. `Sub` just can't access them directly from its own code. – Ian McLaird Mar 29 '15 at 04:55
  • @lan McLaird suppose in above case we define a same field id in Sub class now is it overriding the private field of Super class in Sub class..?? – sandiee Mar 29 '15 at 05:11
  • No. See http://stackoverflow.com/questions/2000137/overriding-private-methods-in-java – Ian McLaird Mar 29 '15 at 05:12
  • @lan McLaird as you said that the private members are inherited an are still there. Moreover we cant override them. Does it mean the id field declared in class Sub will be a new Field. If yes, then isn't there two fields with the same..?? – sandiee Mar 29 '15 at 05:19
  • 1
    "How can you initialize instance field of a class without instantiating it?" If `AbstractSuper` is an abstract class, and `Sub` is a concrete class that extends it, then when you instantiate a new `Sub`, the new object is also an instance of `AbstractSuper`. (See Ian's first comment.) Therefore, it also has the instance fields you defined for `AbstractSuper`. So, in a way, you _have_ instantiated an `AbstractSuper`, i.e. you've created an object that's an instance of `AbstractSuper`. You just have to do it via a concrete subclass. – ajb Mar 29 '15 at 05:20
  • 1
    @sandiee, yes there are now two different fields with the same name, but that's OK, because they're in different namespaces or scopes. The names don't collide. `Super` doesn't know about `Sub`s member, and `Sub` can't see `Super`'s, so there's no confusion to the compiler about which is which. – Ian McLaird Mar 29 '15 at 05:24

3 Answers3

4

I think you're confused about what happens when you use the extends keyword. What that keyword means is that a Sub is a more-specific kind of Super. By the Liskov Substitution Principle, all of the properties of Super must hold for Sub as well. That means that all of Super's private members (methods and properties) are present in an instance of Sub. It's just that for organizational reasons, the developer of Super decided that they didn't want any derived classes messing around with it directly.

Now, how does this relate to memory allocation? In the case of Java, you are correct that the constructor does not allocate memory. It just initializes the fields. The memory allocation is handled by the runtime, and it allocates enough for the whole picture. Remember, a Sub is a Super and then some. So it allocates enough memory to hold everything from the entire inheritance chain all the way back up through java.lang.Object.

abstract classes can, in fact be initialized, or even force their derived classes to initialize their members. For example:

public abstract class Super {
    private int id;
    public Super(int id) {
        this.id = id;
    }
    public int getId() { return this.id; }
}

public class Sub extends Super {
    public Sub() {
        super(5); // failure to call this constructor is a compiler error
    }
}

Now, because Sub can't see Super's private id field, it's free to declare a new one of its own. This does not override Super's field. Any of Super's methods that use that field will still use the one from Super. This could be a little confusing, so the best advice is don't think of it that way. Generally, you'll want to override methods not fields.

Ian McLaird
  • 5,507
  • 2
  • 22
  • 31
  • 1
    @sandiee what Ian says in the code comment is that *not* calling the constructor in the superclass would lead to a compiler error - it demonstrates as he said "`abstract` classes can, in fact be initialized, or even force their derived classes to initialize their members". – Jesper Mar 29 '15 at 07:21
1

I totally agree with the answer of Ian. Totally. Regarding the title of your question,

Does inheritance violates the basic law of oops..?

the answer is it depends. There is a kind of inheritance that violates encapsulation principle: implementation inheritance.

You're using implementation inheritance every time you inherit (through extends primitive) from a class that is not marked as abstract. In that case, to know how to implement your subclass, you need to know the implementation (a.k.a. the code) of methods of the base class. When you override a method, you have to know exactly which is the behavior of that method in the base class. This kind of code reuse is often referred to as white-box reuse.

Quoting the GoF's book, Design Pattern:

Parent classes often define at least part of their subclasses' physical representation. Because inheritance exposes a subclass to details of its parent's implementation, it's often said that "inheritance breaks encapsulation".

So, to reduce implementation dependencies, you have to follow one of the principles of reusable object-oriented design, which is:

Program to an interface, not an implementation

riccardo.cardin
  • 7,971
  • 5
  • 57
  • 106
0

inheritance only concern about what and how is accomplished, not what is promised. If you violate the promises of the base class, what will happen? is there any guarantee that makes you sure it's compatible? -even your compiler will not understand this mistake and you will face a bug in your codes. Such as:

class DoubleEndedQueue {

    void insertFront(Node node){
        // ...
        // insert node infornt of queue
    }

    void insertEnd(Node node){
        // ...
        // insert a node at the end of queue
    }

    void deleteFront(Node node){
        // ...
        // delete the node infront of queue
    }

    void deleteEnd(Node node){
         // ...
        // delete the node at the end of queue
    }

}

class Stack extends DoubleEndedQueue {
        // ...
}

if the class wants to use inheritance with aim of code reuse, It may inherit a behavior that violates its principal, such as insertFront. Let's also see another code example:

public class DataHashSet extends HashSet {
    private int addCount = 0;

    public function DataHashSet(Collection collection) {
            super(collection);
    }

    public function DataHashSet(int initCapacity, float loadFactor) {
            super(initCapacity, loadFactor);
    }

    public boolean function add(Object object) {
            addCount++;
            return super.add(object);
    }

    public boolean function addAll(Collection collection) {
            addCount += collection.size();
            return super.addAll(collection);
    }

    public int function getAddCount(Object object) {
            return addCount;
    }
}

I just reimplement HashSet with DataHashSet class in order to keep track of inserts. In fact, DataHashSet inherit and is a subtype of HashSet. we can instead of HashSet just pass DataHashSet(in java is possible). Also, I do override some of the methods of the base class. Is this legitimate from Liskov substitution principle? As I do not make any changes in the behavior of base class just add a track to insert actions, It seems perfectly legitimate. But, I will argue this is obviously a risky inheritance and a buggy code. First, we should see what exactly add method do. add one unit to related property and call parent class method. There is a problem with that called yo-yo. Look at addAll method, first, it adds collection size to related property then call addAll in the parent, but what exactly parent addAll do? It will call add method several times(loop over the collection), which add will be called? the add in the current class, so, the size of count will be added twice. once when you call addAll and second when parent class will call add method in the child class, that's why we call it yo-yo problem. And another example, imagine:

class A {
    void foo(){
        ...
        this.bar();
        ...
    }
    void bar(){
        ...
    }
}

class B extends A {
    //override bar
    void bar(){
        ...
    }
}

class C {
    void bazz(){
        B b = new B();
        // which bar would be called?
        B.foo();
    }
}

As you see in bazz method which bar will be called? the second one the bar in class B will be called. but, what is the problem here? the problem is foo method in class A will not know anything about the override of bar method in class B, Then your invariants may be violated. because foo may expect the only behavior of bar method that is in own class, not something is overridden. This problem is called fragile base-class problem.

Alireza Rahmani Khalili
  • 2,727
  • 2
  • 32
  • 33