From: Rhino on 23 May 2010 15:29 Lew <noone(a)lewscanon.com> wrote in news:hta80e$l5b$1(a)news.albasani.net: > Lew wrote: >>> Are you familiar with the difference between interfaces and classes? > > Rhino wrote: >> I'm not sure how to answer that. I've read formal definitions of both >> and have written both and gotten them to run. But even after all the >> time I've spent writing Java - I started in 1997 but had a 4 year gap >> that ended a few months back where I wrote no Java at all - I don't >> feel solid on a lot of the theory. Maybe I'm expecting too much of >> myself but I feel like I should know instantly and intuitively what >> the key differences are between classes and interfaces and not have >> to wrestle with "should I use an interface or class here". > > The Java tutorial describes the difference, but doesn't really address > your question, so I'll take a stab. > > Interfaces are pure contract - they describe the signatures of the > methods that class instances must implement, but may not contain any > method implementation nor instance members. (It's also usually a bad > idea to give them 'static' members.) > > Classes may contain some implementation, and must be completely > implemented if not 'abstract'. > > A class can implement an interface - that is, it is a subtype of the > interface that fills in the missing implementation details. > > So you can have an interface: > > public interface Foo > { > public void fooishBehavior(); > } > > Notice the semicolon instead of a method body - no curly braces in the > method. > It's a promise that there will be such a method in any class that > implements > the interface. > > You can have an implementing class: > > public class FooImpl implements Foo > { > public void fooishBehavior() > { > } > } > > The class's claim that it 'implements Foo' requires it to implement > the 'Foo' methods, or at least be an abstract class. We'll ignore > abstract classes for you to study on your own. > No worries; I've created and used some abstract classes in the past. I was going to say they seemed quite straightforward but maybe I should look into them again, just to make sure I'm not failing to consider important aspects! But I'll do that on my own and post if I have questions. Having already read your note twice, I'm starting to have trouble distinguishing between an interface that contains an abstract method and an abstract class that has an abstract method. But I should probably mull this over a bit more before attempting any followup questions. I don't think I understand the interface thoroughly yet so no point in muddying the waters with abstract classes just yet.... > The interface is a type - this is the key. All subtype classes or > interfaces are necessarily also of that type. 'extends' and > 'implements' both express a subtype relationship, and a subtype thing > /is-a/ thing of its parent types. (Inheritance expresses /is-a/; > membership, a.k.a. composition, expresses /has-a/.) > > The key is to think in terms of types, not classes. Interfaces are > pure expressions of type, and classes express a way for the type to do > something actual. > > Different implementors of an interface can do quite different things, > but they must do the things promised by the type they implement. > > Think of "type" as a contract - it shall have these behaviors! > > All implementors of 'Foo' above must implement (or pass on the > responsibility abstractly to implement) that 'fooishBehavior()' > method. How they do so is up to them. So, because Set is an interface, all of its implementors, including HashSet, LinkedHashSet and TreeSet, need to implement all of its (non- abstract) methods. But HashSet can implement the contains() method differently than TreeSet does if that seems advisable. > Variables have a type - that's what's important. When you use a > variable of type 'Foo', all you really care about is to use its > 'fooishBehavior()'. > I always tend to think of variables as things like String greeting = "Hello"; from my COBOL days. But you're using variable where I might say instance, right? As in this case, where the variable myform is being instantiated: Form myForm = new Form(); I'm pretty sure you mean the latter because 'myForm' in this case presumably has some number of behaviours (methods) to do this and that. Then again, by virtue of being a String, 'fred' has behaviours too, such as length() and substring(). Hmm, maybe this is a "distinction without a difference". After all, String greeting = "Hello"; is equivalent to: String greeting = new String("Hello"); > You should not (usually - always the disclaimer) care how the thing > does its 'fooishBehavior()'. > > So you typically have a construct like > > Foo foo = new FooImpl(); > > Since everything of a subtype ('FooImpl') /is-a/ thing of the > supertype ('Foo'), this is legal, and since 'Foo' is the type you care > about, this is proper. > Or, to use an example from the API: Set<String> mySet = new TreeSet<String>(); Would you consider that a parallel example? In other words, in your example, was Foo an interface while FooImpl was a class? > Later you might refactor the code. Perhaps you discover that > 'FooImpl#fooishBehavior()' is not thread safe but you need it to be. > However, the logic of the program doesn't need to know that, only that > 'foo' has the method, safe or not. So you change that initialization > to: > > Foo foo = new ConcurrentFooImpl(); > Since I'm not 100% sure whether you mean Foo to be an interface or a class, let me just ask if you're saying that your example is logically equivalent to changing: Set<String> mySet = new TreeSet<String>(); to Set<String> mySet = new HashSet<String>(); In my example, you may have decided that the performance benefits of the HashSet outweigh the fact that your data is in alphabetical order within the TreeSet. > The rest of the program, knowing only that 'foo' is of type 'Foo', > needs no rewrite. The hidden secret of the refactored 'foo' buys you > thread safety, and the rest of the program needs no recompile. Magic! > > This came up in a project where I worked when we substituted something > like > > Map <Foo, Bar> whatever = Collections.synchronizedMap( > new HashMap <Foo, Bar> () ); > > with > > Map <Foo, Bar> whatever = new ConcurrentHashMap <Foo, Bar> (); > > and got a huge boost in the program's performance. > You have to love it when a one line change makes a big improvement like that :-) -- Rhino
From: Lew on 23 May 2010 15:57 Arne Vajhøj wrote: >> I18N is a well-known counter-argument to YAGNI. Rhino: > YAGNI? Sorry, I don't know that acronym..... <http://www.google.com/search?q=YAGNI+acronym> GIYF. Sometimes you should put in a little effort yourself. -- Lew
From: Lew on 23 May 2010 16:43 Lew wrote: >>>> Are you familiar with the difference between interfaces and classes? .... >> The class's claim that it 'implements Foo' requires it to implement >> the 'Foo' methods, or at least be an abstract class. We'll ignore >> abstract classes for you to study on your own. Rhino wrote: > Having already read your note twice, I'm starting to have trouble > distinguishing between an interface that contains an abstract method and > an abstract class that has an abstract method. But I should probably mull > this over a bit more before attempting any followup questions. I don't > think I understand the interface thoroughly yet so no point in muddying > the waters with abstract classes just yet.... An interface MUST NOT have any implementation of its methods. It's pure type. An abstract class MAY have implementation for any or all of its methods. It's type with some implementation. A type may inherit (extend or implement) any number of interfaces. A class may only extend from one class. Lew wrote: >> The key is to think in terms of types, not classes. Interfaces are >> pure expressions of type, and classes express a way for the type to do >> something actual. Rhino wrote: > So, because Set is an interface, all of its implementors, including > HashSet, LinkedHashSet and TreeSet, need to implement all of its (non- > abstract) methods. There are no non-abstract methods in an interface. > But HashSet can implement the contains() method > differently than TreeSet does if that seems advisable. Correct. Rhino wrote: > I always tend to think of variables as things like > > String greeting = "Hello"; > > from my COBOL days. But you're using variable where I might say instance, right? No. An instance is the object itself. A variable is a pointer to the instance. > As in this case, where the variable myform is being instantiated: > > Form myForm = new Form(); No, the variable is being initialized. The instance is being instantiated. ("Instance", "instantiate" - see the connection?) > I'm pretty sure you mean the latter because 'myForm' in this case > presumably has some number of behaviours (methods) to do this and that. No, the instance has behaviors. The variable only gives you access to invoke those behaviors. > Then again, by virtue of being a String, 'fred' has behaviours too, such > as length() and substring(). Hmm, maybe this is a "distinction without a > difference". After all, I don't know what you're talking about here. Again, the variable does not have behaviors, it only gives you (possibly limited) access to those behaviors by pointing to the object that actually does have the behaviors (and possibly others to which the variable does not give access). > > String greeting = "Hello"; > > is equivalent to: > > String greeting = new String("Hello"); No, those are not at all equivalent. > Or, to use an example from the API: > > Set<String> mySet = new TreeSet<String>(); > > Would you consider that a parallel example? In other words, in your > example, was Foo an interface while FooImpl was a class? Did you actually *read* the sample code I provided for 'Foo' and 'FooImpl'? The answer is there: >> So you can have an interface: >> >> public interface Foo >> { >> public void fooishBehavior(); >> } .... >> You can have an implementing class: >> >> public class FooImpl implements Foo >> { >> public void fooishBehavior() >> { >> } >> } Tch, tch. Rhino wrote: > Since I'm not 100% sure whether you mean Foo to be an interface or a > class, let me just ask if you're saying that your example is logically I really don't get how you aren't. I get the feeling you aren't paying attention. > equivalent to changing: > > Set<String> mySet = new TreeSet<String>(); > > to > > Set<String> mySet = new HashSet<String>(); > > In my example, you may have decided that the performance benefits of the > HashSet outweigh the fact that your data is in alphabetical order within > the TreeSet. What performance benefits? Given that you need results in sorted order, you are nearly certain not to have any. Even without that, what performance benefits? Performance is never an argument that wins over logical correctness. "I can give you wrong answers in half the time of correct ones!" -- Lew
From: Eric Sosman on 23 May 2010 16:42 On 5/23/2010 2:53 PM, Rhino wrote: > Lew<noone(a)lewscanon.com> wrote in news:hta0s6$dmk$1(a)news.albasani.net: >> >> I strongly advise you, again!, to stick with SSCCEs until you stop >> making that kind of mistake. That you have not learned your lesson >> about posting uncompilable code is starting to make you look careless >> and lazy. >> > Honestly, I think you're being just a little too rigid now. Rhino, you are asking strangers for free help, free advice, free assistance. Said strangers are accustomed to being paid for exercising their expertise, but for reasons of their own they put it at your disposal gratis. Under the circumstances, you are in no position to dictate terms, much less to insist that they put up with your persistent (intentional?) sloppiness. If you'll play by my rules, I'm willing to try to help. But if you insist on mocking them, I'll take my ball and go home. Other potential helpers will have different preferences, and different sticking points -- but sooner or later, you will have to do things their way or pay them enough to put up with you. Can't speak for others, but as for me: Mend your ways, or I will go mine. Beggars can't be choosers. TANSTAAFL. -- Eric Sosman esosman(a)ieee-dot-org.invalid
From: Lew on 23 May 2010 16:54
Please trim your posts. Rhino wrote: > Right now, I think I would benefit from the answer to a new mystery. Should have a new thread, then. > I do database stuff fairly frequently and mostly use my copy of DB2 as my > database engine. Naturally, I use ResultSets for a lot of this work. I > know that ResultSet is an interface, not a class, but it is rich in > exactly the sorts of methods I need to grab the Strings, integers and > whatnot in the database or to write them to the database. A short time > ago, I was looking at the source for ResultSet and found that not one of > the many methods in that interface are implemented; every single method > seems to be abstract. I see in the JavaDoc that there are a number of > "sub-interfaces" - I'm really not sure what a sub-interface is and how it > is different from a interface and that it has a "super-interface" - > again, I'm not sure what that is! - but the perplexing thing is that I am > not explicitly using the super-interface or any of the sub-interfaces yet > my code still works fine. That kind of thing disorients me; I wonder how > that could possibly be working and why I don't need to change from > ResultSet to a real class or another sub-interface or whatever. My > pragmatic self is capable of just ignoring all of that and saying "It's a > mystery but I'm not going to question it since it obviously works." But > my more idealistic self is bothered that it isn't obvious to me why the > ResultSet works despite its troubling aspects. > > Can you possibly shed some light on what is happening there? Yes. OK, I will actually do so. 'ResultSet' is not implemented in the standard Java API, but in the JDBC driver. The instantiating class is always a subtype of 'ResultSet' specific to that driver. The details are hidden by the driver library. That's the WHOLE POINT of interface-driven programming (a subset of type-driven programming)! ALL you need to know is the interface! You want to AVOID the impulse "to change ... to a real [sic] class or another sub-interface or whatever". 'ResultSet' works, like all interface-declared variables, because the variable always points to an actual object which is an instance of a class. VARIABLES ARE POINTERS! The actual action happens in the object to which the variable points. This is the heart and soul of polymorphism - you refer (point) to a supertype, but the behavior is enacted by an instance of the subtype. All the variable does is give you access to the behavior through the public members of the variable's type. That access is always to the actual behavior of the instance. VARIABLES ARE POINTERS! All your code cares about is that 'ResultSet' has certain behaviors. Those are the behaviors promised by the type. That way, when you change databases, say from (blecch!) MySQL to (ahhhh!) PostgreSQL, you don't have to rewrite your code much. You still have a 'ResultSet' whose members are the members your code is already using; at run time the JDBC driver returns a pointer to the actual instance to the 'ResultSet' variable. VARIABLES ARE POINTERS! -- Lew |