LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-18-2015, 10:00 PM   #1
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Rep: Reputation: 31
java - constructor and varaible instantiation


Hi, I'm new to java language. Consider this class A. It looks fine.

Code:
public class A {
  public List<String> lstStr;
  public int count;
  public A() {
    lstStr = new ArrayList<String>();
    count = 0;
  }
}
Suppose I need to reuse the list and member variables. I need a reset() function:

Code:
public class A {
  public List<String> lstStr;
  public int count;
  public A() {
    lstStr = new ArrayList<String>();
    reset();
  }
  public void reset() {
    lstStr.clear();
    count = 0;
  }
}
Now I need a class B that extends A. Similarly I need a reset() for the member variables:

Code:
public class B extends A {
  public List<Double> lstDbl;
  public double length;
  public B() {
    lstDbl = new ArrayList<Double>();
    reset(); /*line X*/
  }
  @Override
  public void reset() {
    lstDbl.clear(); /*line Y*/
    length = 0.0;
  }
}
Got stuck here.
Observations:
1. line Y throws nullpointer exception upon an instance of B is new'ed.
2. A.reset() is hidden and never called.
3. line X seems repeated because A() will call reset() anyway. But it looks more complete with it.

So how to tackle this kind of typical reset() problem?
Or what is the correct way to initialize and reset?
 
Old 01-19-2015, 12:03 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,869
Blog Entries: 1

Rep: Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870
You might try calling 'super.reset' in 'B.reset'.
 
Old 01-19-2015, 02:14 AM   #3
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Helps a little but not quite.

Should I take away reset() from the ctor and rely on the user to reset() before every use?
Code:
public class A {
  public List<String> lstStr;
  public int count;
  public A() {
    lstStr = new ArrayList<String>();
  }
  public void reset() {
    lstStr.clear();
    count = 0;
  }
}

public class B extends A {
  public List<Double> lstDbl;
  public double length;
  public B() {
    lstDbl = new ArrayList<Double>();
  }
  @Override
  public void reset() {
    super.reset();
    lstDbl.clear();
    length = 0.0;
  }
}
 
Old 01-19-2015, 04:45 AM   #4
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,869
Blog Entries: 1

Rep: Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870
try this:
Code:
class A {
  public List<String> lstStr;
  public int count;
  public A() {
    lstStr = new ArrayList<String>();
    my_reset();
  }
  private void my_reset() {
    lstStr.clear();
    count = 0;
  }
  public void reset() {
    my_reset();
  }
}

class B extends A {
  public List<Double> lstDbl;
  public double length;
  public B() {
    lstDbl = new ArrayList<Double>();
  }

  @Override
  public void reset() {
    super.reset();
    lstDbl.clear();
    length = 0.0;
  }
}
 
Old 01-19-2015, 08:08 AM   #5
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,671
Blog Entries: 4

Rep: Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945
From a design standpoint, if you find yourself defining subclasses that "[have to] know about the guts of" the workings of their parents, then you probably ought to re-think that design. A particular telltale sign is when classes have many things that are declared to be public

Instead of thinking of the classes as mere "data containers," exposing their inner workings (their variables ...) for all the world to see and therefore to mess-with, think of them as "service providers."

For instance, objects of your class A, or any descendent thereof, provide the service of storing 'things' in some kind of a list-wise fashion. These objects so-far provide three services to all who come:
  • A "count" property, which tells you the number of 'things' being stored.
  • A "List" property, which gives access to the 'things' themselves.
  • A "reset" method, which empties the "List."

Parent-class "A" is, in fact, an abstract method: it defines all of the things which all of its children must do, must provide, and therefore must implement ... but it does not specify the implementation, itself. (It also should not specify the data type of any particular child-class, since this is obviously intended to vary from child to child, as being probably the only significant difference between the various children.)

The implementation of all of the child-methods must be compatible with what their abstract ancestor has set forth. (The language, whatever language it is, will see to that ...) But that implementation should be concealed. You don't know exactly how it was built: you can only see and use what it does. Code outside of the class cannot directly affect the implementation of the class; can't dabble with things that it has no business dabbling with; and can't invoke the properties and methods in the "wrong" way. A well-designed class structure leverages the ability of the language to reward mistakes with compile-time errors.
 
Old 01-19-2015, 09:33 AM   #6
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Thanks.

So this makes more sense:

Code:
// The below is what I need to know about A.
class A {
  public void reset() { ... } // guarantee to reset A to its initial state
}

// I need to write my own B that extends A:
class B extends A {
  private List<Double> lstDbl;
  private int resetCount = 0;
  public B() {
    reset();
  }
  public void reset() { // guarantee to reset B to its initial state
    super.reset();
    if (lstDbl == null) lstDbl = new ArrayList<Double>();
    lstDbl.clear();
    ++resetCount;
  }
}
This piece of code works fine. But resetCount is not quite controllable. Although trivial, it has impact to memory and CPU. When trivial things are ignored, how important can we become?
 
Old 01-19-2015, 09:53 AM   #7
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,930

Rep: Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320Reputation: 7320
that depends on the number of instances. Actually you may try to print its value before exiting to see that. Probably also there can be multithreading issue.
 
Old 01-19-2015, 10:15 AM   #8
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,869
Blog Entries: 1

Rep: Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870
> But resetCount is not quite controllable.

Exactly what does that mean?
 
Old 01-19-2015, 07:19 PM   #9
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Since B does not care or should not care the implementation of A, B can only rely on A to do its job. So it is not up to B to control when A should call reset(): A may or may not already called reset() in its own ctor.

I guess it is a price to pay when B chooses to override reset().
 
Old 01-19-2015, 08:34 PM   #10
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,671
Blog Entries: 4

Rep: Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945
What you have proposed here is, of course, "neither right nor wrong," but I did want to very briefly clarify what I was referring to when I called class A an "abstract (parent ...) class."

In my experience, designers often like to "first, define a general rule" in the parent classes, which are abstract, and then to define the several children which they actually use in their code.

To clarify this idea, I'm going to introduce some new class-names:
  • "A" becomes Abstract_ListContainer.
  • A child-class corresponding to the present concrete-implementation of "A" becomes ListContainer_Integer.
  • "B" becomes ListContainer_Float.
The Abstract_ListContainer abstract class becomes a single conceptual umbrella under which you can "typecast" all of the ListContainer behaviors. Every "ListContainer," in order to be called a "ListContainer," will conform to these specifications, varying only in their particulars (namely: the data-type that it is prepared to store).

The two child-classes, then, are concrete implementations of the abstract design-pattern. They're the ones that actually get down to brass-tacks ... as they must, of course, since they're the only ones that will ever actually be instantiated.

"And so, why, exactly, do we go to all this trouble?" There are, I think, two excellent reasons:

(1) Human expressiveness: It is a quite-natural thing for us ... us humans ... to think in terms of "first, a sweeping generalization ... then, specifics." When first we wave our hands in the air, we exploit our extraordinary powers of abstract visualization (which a digital computer, of course, knows nothing of). Then, and only then, do we "get down to details."

(2) Compile-time error detection: Programming errors are very subtle, so we want to harness the computer's utterly mindless abilities, in order to flush-out as many runtime error situations as possible, when we compile. So that we never create erroneous code.
 
Old 01-19-2015, 10:08 PM   #11
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Red face

Thank you. Your reply helps me rethink about OO languages and the work I have done so far.

Instead of extending a MountainBike from a RoadBike because of shorter development time, I should be planning Vehicle seriously from the beginning.

---

Regarding the reset() observation, I have asked a friend from a Java background and his reply is that java people seldom think about 'reset' but instead a new instance every time a fresh start is needed. They don't bother to clear and reuse a list variable but instead assign a new list to the same variable and let GC handle the dangling allocation. That's what java is. If detailed performance and resource requirements are in place, C or C++ may be the more appropriate choice.

Just some personal comments:
I love Assembly but poor at it.
I love C/C++ and ok at it.
I hate Java but need to learn and live with it.
 
Old 01-20-2015, 03:03 AM   #12
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,869
Blog Entries: 1

Rep: Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870
Nonetheless, an unanswered question or an unsolved problem is like an open wound (if minor). So I suggest you read my previous post #4
 
Old 01-20-2015, 05:47 AM   #13
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Agree that the question is unanswered and still bleeding. I'll keep it open for a while.

In a sense the code #4 is designed to have two different entry points of resetting by A. A::A() is not calling reset() so that B::reset() won't be called at initialization. Although not natural to write it that way, it works too.

Code:
// This is what Java people (my friend) do:
B b;
b = new B();
... // use b
b = new B();
... // use b again.  b is like being reset.  Java people don't bother with reset.
b = new B();
... // and again and again.
Code:
// This is what C++ people (I) do:
B *b = new B;
... // use b
b->reset(); // this is what I do for control.
... // use b again
b->reset();
... // and again and again.
delete b;
 
Old 01-20-2015, 09:05 AM   #14
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,671
Blog Entries: 4

Rep: Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945
I wouldn't go so far as to say, Vehicle. Bicycle will do nicely.

(Also: everything I am saying applies to all languages of this sort ... pick your poison.)

Now, let's pursue that bicycle-idea just a little bit. You can usefully describe "a generic bike," although you can never buy one. Ex minimis, every "bike" has certain properties that are common to all "bikes," and certain things (ride(), park(), crash()) that you can do with them or to them.

It might even be useful to define some of these properties or activities "generically," placing these in the Bicycle class, and perhaps defining these so that they invoke methods or access properties that are defined (must be defined ...) by specific subclasses such as RoadBike. (Maybe, those properties/methods are protected so that they can only be accessed by such means; they can't be accessed directly "from the outside." In the parent class, these methods/properties are abstract so that the language, itself, requires that the descendents must override them.)

Sometimes, it's advantageous to say, "RoadBike does things exactly like any Bike does ... except ..." In situations like that, a child class can override the property/method of its ancestor, and then, within that handler, invoke the handler of its ancestor.

But what you want to be very careful of, IMHO, is: "diddling with the guts of anything." Once I have found the piece-of-code that is responsible for doing something, I don't want to be surprised by anything that I cannot see "in that particular set of source-code paragraphs." If I've determined that a bug is manifesting itself in this-or-that location, then I want the insect to be ... there. If there is "an exception to the rule," then I want the source-code to very plainly say that, and I want the language compiler to be my "enforcer," such that source-code which does not meet those strictures cannot compile. (Ergo, if it does compile, it must conform.)
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Constructor takes string => constructor not called...? (C++) JohnGraham Programming 4 02-16-2012 12:37 PM
java: intialize object/variable inside constructor vs outside kpachopoulos Programming 5 09-05-2006 12:05 AM
JAVA: Can an initialization block take parameters from the constructor? byteframe Programming 9 04-14-2006 10:51 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:43 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration