Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #37169 > unrolled thread
| Started by | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| First post | 2017-08-13 11:47 +0200 |
| Last post | 2017-08-13 12:03 -0500 |
| Articles | 13 — 4 participants |
Back to article view | Back to comp.lang.java.programmer
Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-13 11:47 +0200
Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-13 10:59 +0000
Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-13 11:38 +0000
Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-13 15:43 +0200
Re: Using main from abstract class in concrete class Eric Sosman <esosman@comcast-dot-net.invalid> - 2017-08-13 10:32 -0400
Re: Using main from abstract class in concrete class Eric Sosman <esosman@comcast-dot-net.invalid> - 2017-08-13 10:37 -0400
Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-13 17:17 +0200
Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-17 18:56 +0000
Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-18 06:37 +0200
Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-18 19:48 +0000
Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-18 23:37 +0200
Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-19 01:32 +0200
Re: Using main from abstract class in concrete class Joshua Cranmer 🐧 <Pidgeot18@verizon.invalid> - 2017-08-13 12:03 -0500
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-08-13 11:47 +0200 |
| Subject | Using main from abstract class in concrete class |
| Message-ID | <87h8xbx0ig.fsf@munus.decebal.nl> |
I have an abstract class. There can be several concrete classes that extend this class. Is it possible to write a main in the abstract class which will be used by the concrete classes and that in the main a instance of the concrete class is created? -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [next] | [standalone]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-08-13 10:59 +0000 |
| Message-ID | <slrnop0cga.o2q.avl@logic.at> |
| In reply to | #37169 |
Cecil Westerhof <Cecil@decebal.nl> wrote: > I have an abstract class. There can be several concrete classes that > extend this class. Is it possible to write a main in the abstract > class which will be used by the concrete classes and that in the main > a instance of the concrete class is created? The first part of the question is trivially yes: derived classes that don't provide their own main() will get your "abstract" class's main(). I guess, you knew that already. For the other part, https://stackoverflow.com/questions/939932/how-to-determine-main-class-at-runtime-in-threaded-java-application seems to imply that short of some non-reliable environment variables or system properties there is no reliable way to know which class was originally started.
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-08-13 11:38 +0000 |
| Message-ID | <slrnop0ep7.o2q.avl@logic.at> |
| In reply to | #37173 |
Andreas Leitgeb <avl@logic.at> wrote: > Cecil Westerhof <Cecil@decebal.nl> wrote: >> I have an abstract class. There can be several concrete classes that >> extend this class. Is it possible to write a main in the abstract >> class which will be used by the concrete classes and that in the main >> a instance of the concrete class is created? > > The first part of the question is trivially yes: derived classes that > don't provide their own main() will get your "abstract" class's main(). > I guess, you knew that already. > > For the other part, > https://stackoverflow.com/questions/939932/how-to-determine-main-class-at-runtime-in-threaded-java-application > seems to imply that short of some non-reliable environment variables > or system properties there is no reliable way to know which class was > originally started. maybe a workaround: Make your abstract class the real main class, and just pass it the name of the requested subclass as first argument: java your.path.AbstractMain users.path.ConcreteSub ... (and write the AbstractMain.main method accordingly)
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-08-13 15:43 +0200 |
| Message-ID | <871sofwpl8.fsf@munus.decebal.nl> |
| In reply to | #37169 |
ram@zedat.fu-berlin.de (Stefan Ram) writes:
> Cecil Westerhof <Cecil@decebal.nl> writes:
>>I have an abstract class. There can be several concrete classes that
>>extend this class. Is it possible to write a main in the abstract
>>class which will be used by the concrete classes and that in the main
>>a instance of the concrete class is created?
>
> The noun phrase »a main« does not have a general meaning in the
> Java community. I assume you mean a method with the well-known
> proclamation
>
> public static void main( final java.lang.String[] args )
Yes, that was what I mend. I should have been more clear.
>
> . Main.java
>
> abstract class Abstract
> {
> public static void main( final java.lang.String[] args )
> { try
> { java.lang.Class.forName( args[ 0 ]).
> getDeclaredConstructor().newInstance(); }
> catch
> ( final
> java.lang.ClassNotFoundException |
> java.lang.NoSuchMethodException |
> java.lang.InstantiationException |
> java.lang.IllegalAccessException |
> java.lang.reflect.InvocationTargetException
> exception )
> { java.lang.System.err.println( exception ); }}}
>
> public final class Main extends Abstract
> {
>
> public Main()
> { java.lang.System.out.println( "new Main()" ); }
>
> public static void main( final java.lang.String[] args )
> { final java.lang.String[] arguments =
> { Main.class.getCanonicalName() };
> Abstract.main( arguments ); }}
>
> transcript
>
> new Main()
>
At the moment I have:
public static void main(final String[] args) throws SQLException {
SQL.mainWork(SQLite3.class.getCanonicalName(), args);
}
And in SQL.java I have:
static void mainWork(final String className, final String[] args)
throws SQLException {
String action;
String database;
String[] parameters;
if (args.length < 2) {
System.err.println("Need at least two parameters: command and database.");
System.exit(1);
}
// First argument is action
// Second argument is database
action = args[0];
database = args[1];
parameters = Arrays.copyOfRange(args, 2, args.length);
try {
SQL connection = (SQL) Class.forName(className)
.getDeclaredConstructor(new Class<?>[] {String.class})
.newInstance(database);
switch (action) {
case "--testConnection":
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2017-08-13 10:32 -0400 |
| Message-ID | <ompnlf$7j6$1@dont-email.me> |
| In reply to | #37169 |
On 8/13/2017 5:47 AM, Cecil Westerhof wrote:
> I have an abstract class. There can be several concrete classes that
> extend this class. Is it possible to write a main in the abstract
> class which will be used by the concrete classes and that in the main
> a instance of the concrete class is created?
It is certainly possible for an abstract class to implement a
`public static void main(String[])' method, and it is also possible
for the JVM to start executing your program by calling that method.
That method can create instances of any (accessible) class it
wants, including concrete subclasses of its own abstract class.
There is, however, no automatic way for the method to learn about
any particular class -- since the method is `static' it has no `this'
on which it could call getClass(), for example. So the method will
either need to know or be told what class to instantiate:
public abstract class Abstract {
public static void main(String[] args) {
// "I know what I want"
Abstract known = new ConcreteSubclass();
// "I do what I'm told"
// (exception-handling omitted)
Class<?> clown = Class.forName(args[0]);
Abstract learned = (Abstract) clown.newInstance();
...
}
}
Finally, as to "used by the concrete classes" -- it's a `public'
method, so methods of the subclasses can certainly call it if that's
what you mean by "use." What *won't* work is to tell the JVM to run
the main() method of a subclass that doesn't actually have one, and
have the JVM somehow know to run Abstract::main in its place. Static
methods are not inherited (nor inheritable). You could give each
concrete subclass its own main() that in turn calls the main() of
the abstract class:
class ConcreteSubclass extends Abstract {
public static void main(String[] args) {
Abstract.main(args);
// super.main(args) might work; not sure off-hand
}
}
However, in this situation I think it'd be simpler for the subclass
to do its own instantiating and just hand the object to a method of
the superclass:
public abstract class Abstract2 {
protected static void start(Abstract2 obj, String[] args) {
// obj is the desired instance
...
}
}
class Concrete2 extends Abstract2 {
public static void main(String[] args) {
Abstract.start(new Concrete2(), args);
}
}
--
esosman@comcast-dot-net.invalid
Twelve hundred fifty-six days to go.
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2017-08-13 10:37 -0400 |
| Message-ID | <ompnve$8g6$1@dont-email.me> |
| In reply to | #37179 |
On 8/13/2017 10:32 AM, Eric Sosman wrote:
> [...]
> What *won't* work is to tell the JVM to run
> the main() method of a subclass that doesn't actually have one, and
> have the JVM somehow know to run Abstract::main in its place.
... for suitable values of "*won't*", such as (for example)
"WILL CERTAINLY".
Sorry about that.
--
esosman@comcast-dot-net.invalid
Twelve hundred fifty-six days to go.
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-08-13 17:17 +0200 |
| Message-ID | <87wp67v6of.fsf@munus.decebal.nl> |
| In reply to | #37179 |
Eric Sosman <esosman@comcast-dot-net.invalid> writes:
> However, in this situation I think it'd be simpler for the subclass
> to do its own instantiating and just hand the object to a method of
> the superclass:
>
> public abstract class Abstract2 {
> protected static void start(Abstract2 obj, String[] args) {
> // obj is the desired instance
> ...
> }
> }
>
> class Concrete2 extends Abstract2 {
> public static void main(String[] args) {
> Abstract.start(new Concrete2(), args);
> }
> }
I do something like that now:
public class SQLite3 extends SQL {
// ################ main
public static void main(final String[] args) throws SQLException {
SQL.mainWork(SQLite3.class.getCanonicalName(), args);
}
The ‘problem’ is that I have to write it for every concrete class, but
that is doable.
I renamed main in the abstract class SQL to mainWork and removed
public.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-08-17 18:56 +0000 |
| Message-ID | <slrnopbpu1.o2q.avl@logic.at> |
| In reply to | #37181 |
Cecil Westerhof <Cecil@decebal.nl> wrote:
> I do something like that now:
> public class SQLite3 extends SQL {
> // ################ main
> public static void main(final String[] args) throws SQLException {
> SQL.mainWork(SQLite3.class.getCanonicalName(), args);
> }
Why not change "mainWork" such, that it accepts a Class ref directly,
rather than the canonical name?
Maybe even simpler would be to have it accept a SQL ref and just pass
it: new SQLite3()
There is certainly more than one way to Rome.
> I renamed main in the abstract class SQL to mainWork and removed
> public.
You might want to add "protected", so that derived classes even in
other packages can still call it. "protected" is more permissive than
default access.
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-08-18 06:37 +0200 |
| Message-ID | <87valljxtp.fsf@munus.decebal.nl> |
| In reply to | #37259 |
Andreas Leitgeb <avl@logic.at> writes:
> Cecil Westerhof <Cecil@decebal.nl> wrote:
>> I do something like that now:
>> public class SQLite3 extends SQL {
>> // ################ main
>> public static void main(final String[] args) throws SQLException {
>> SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>> }
>
> Why not change "mainWork" such, that it accepts a Class ref directly,
> rather than the canonical name?
>
> Maybe even simpler would be to have it accept a SQL ref and just pass
> it: new SQLite3()
>
> There is certainly more than one way to Rome.
The idea is that mainWork is always called from the main of a class.
But I can always ponder about this possibility.
Also I probably make AbstractSQL a concrete class named SQLWrapper.
>> I renamed main in the abstract class SQL to mainWork and removed
>> public.
>
> You might want to add "protected", so that derived classes even in
> other packages can still call it. "protected" is more permissive than
> default access.
It is something to think about. Is there a good reason to want derived
classes in another package?
I am thinking about changing AbstractSQL to SQLWrapper (and removing
abstract) and letting SQLWrapper be called with a URLPrefix, so it can
be used for databases where there is no concrete class for yet.
There are databases that can use in memory databases. For example
sqlite3 uses :memory:. I first had testDB.sqlite as database to test.
I am thinking about changing it to :memory:. Is that good enough, or
should I always check also for a stored database?
For sqlite3 I need to use (also) a ‘real’ database anyway, because I
need to check the lock functionality.
I have unit tests to test AbstractSQL, SQLResultSet and SQLStatement
(the classes I so far defined). I test those classes with the SQLite3
class. Is that good enough, or should they be tested with every
concrete class?
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-08-18 19:48 +0000 |
| Message-ID | <slrnopehbp.o2q.avl@logic.at> |
| In reply to | #37268 |
Cecil Westerhof <Cecil@decebal.nl> wrote:
> Andreas Leitgeb <avl@logic.at> writes:
>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>> I do something like that now:
>>> public class SQLite3 extends SQL {
>>> // ################ main
>>> public static void main(final String[] args) throws SQLException {
>>> SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>>> }
>> Why not change "mainWork" such, that it accepts a Class ref directly,
>> rather than the canonical name?
>>
>> Maybe even simpler would be to have it accept a SQL ref and just pass
>> it: new SQLite3()
>
> The idea is that mainWork is always called from the main of a class.
Yes, that was already pretty clear from your example snippet.
But even a static method of a subclass *can* create an instance of
its own class (and also of any other accessible class):
public class SQLite3 extends SQL {
// ################ main
public static void main(final String[] args) throws SQLException {
SQL.mainWork(new SQLite3(), args);
}
and SQL.mainWork would be declared as taking (SQL sqlSubInstance, String[] args)
If you expect that your abstract class will need to create more
instances of the relevant subclass, then using the factory pattern
might be preferable to repeated .forName'ing.
>> You might want to add "protected", so that derived classes even in
>> other packages can still call it. "protected" is more permissive than
>> default access.
>
> Is there a good reason to want derived classes in another package?
In some earlier posts you expressed your intention to make your class
also usable for others.
If someone else wanted to derive from your abstract SQL class, they
probably wouldn't want to put their derived class in a package starting
with nl.decebal., but probably rather in a package reflecting their
own domain.
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-08-18 23:37 +0200 |
| Message-ID | <87k220iml8.fsf@munus.decebal.nl> |
| In reply to | #37276 |
Andreas Leitgeb <avl@logic.at> writes:
> Cecil Westerhof <Cecil@decebal.nl> wrote:
>> Andreas Leitgeb <avl@logic.at> writes:
>>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>>> I do something like that now:
>>>> public class SQLite3 extends SQL {
>>>> // ################ main
>>>> public static void main(final String[] args) throws SQLException {
>>>> SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>>>> }
>>> Why not change "mainWork" such, that it accepts a Class ref directly,
>>> rather than the canonical name?
>>>
>>> Maybe even simpler would be to have it accept a SQL ref and just pass
>>> it: new SQLite3()
>>
>> The idea is that mainWork is always called from the main of a class.
>
> Yes, that was already pretty clear from your example snippet.
>
> But even a static method of a subclass *can* create an instance of
> its own class (and also of any other accessible class):
>
> public class SQLite3 extends SQL {
> // ################ main
> public static void main(final String[] args) throws SQLException {
> SQL.mainWork(new SQLite3(), args);
> }
>
> and SQL.mainWork would be declared as taking (SQL sqlSubInstance,
> String[] args)
There is some checking done in mainWork. But I could put that in a
separate function and call this from the main and return this to the
main. It makes the mains a little bigger, but removes not that clear
code from mainWork.
Something to implement.
> If you expect that your abstract class will need to create more
> instances of the relevant subclass, then using the factory pattern
> might be preferable to repeated .forName'ing.
At the moment that does not seem very likely. The main function is
only for some simple functions. For example I use it with SQLite to
check the lock status of databases.
>>> You might want to add "protected", so that derived classes even in
>>> other packages can still call it. "protected" is more permissive than
>>> default access.
>>
>> Is there a good reason to want derived classes in another package?
>
> In some earlier posts you expressed your intention to make your class
> also usable for others.
>
> If someone else wanted to derive from your abstract SQL class, they
> probably wouldn't want to put their derived class in a package starting
> with nl.decebal., but probably rather in a package reflecting their
> own domain.
That is a good point. I will change it.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-08-19 01:32 +0200 |
| Message-ID | <87fucoih9a.fsf@munus.decebal.nl> |
| In reply to | #37278 |
Cecil Westerhof <Cecil@decebal.nl> writes:
> Andreas Leitgeb <avl@logic.at> writes:
>
>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>> Andreas Leitgeb <avl@logic.at> writes:
>>>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>>>> I do something like that now:
>>>>> public class SQLite3 extends SQL {
>>>>> // ################ main
>>>>> public static void main(final String[] args) throws SQLException {
>>>>> SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>>>>> }
>>>> Why not change "mainWork" such, that it accepts a Class ref directly,
>>>> rather than the canonical name?
>>>>
>>>> Maybe even simpler would be to have it accept a SQL ref and just pass
>>>> it: new SQLite3()
>>>
>>> The idea is that mainWork is always called from the main of a class.
>>
>> Yes, that was already pretty clear from your example snippet.
>>
>> But even a static method of a subclass *can* create an instance of
>> its own class (and also of any other accessible class):
>>
>> public class SQLite3 extends SQL {
>> // ################ main
>> public static void main(final String[] args) throws SQLException {
>> SQL.mainWork(new SQLite3(), args);
>> }
>>
>> and SQL.mainWork would be declared as taking (SQL sqlSubInstance,
>> String[] args)
>
> There is some checking done in mainWork. But I could put that in a
> separate function and call this from the main and return this to the
> main. It makes the mains a little bigger, but removes not that clear
> code from mainWork.
> Something to implement.
It has become:
public static void main(final String[] args) throws SQLException {
MainWorkParams params = checkArgs(args);
try (SQLite3 sqlite3 = new SQLite3(
params.database,
params.user,
params.password)) {
sqlite3.mainWork(params.action, params.restArgs);
}
}
>>>> You might want to add "protected", so that derived classes even in
>>>> other packages can still call it. "protected" is more permissive than
>>>> default access.
>>>
>>> Is there a good reason to want derived classes in another package?
>>
>> In some earlier posts you expressed your intention to make your class
>> also usable for others.
>>
>> If someone else wanted to derive from your abstract SQL class, they
>> probably wouldn't want to put their derived class in a package starting
>> with nl.decebal., but probably rather in a package reflecting their
>> own domain.
>
> That is a good point. I will change it.
Done.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Joshua Cranmer 🐧 <Pidgeot18@verizon.invalid> |
|---|---|
| Date | 2017-08-13 12:03 -0500 |
| Message-ID | <omq0h2$33q$1@dont-email.me> |
| In reply to | #37169 |
On 8/13/2017 4:47 AM, Cecil Westerhof wrote: > I have an abstract class. There can be several concrete classes that > extend this class. Is it possible to write a main in the abstract > class which will be used by the concrete classes and that in the main > a instance of the concrete class is created? Well, your question is gibberish, but I'm assuming what you're really asking is "can I have a static method that is invoked by dynamic dispatch on the receiver class?" The answer to that question is "not really." So static methods are inherited in scope, such that calling 'Sub.foo' looks for a static method in Sub first and then looks for it in Super if it couldn't find it. But static methods have no concept of a "this" pointer like instance methods do. Thus, there is nothing that could possibly be dispatched on. You can work around this flaw by using Class objects and using reflection to search for the method. Of course, the superclass method still doesn't have a notion of the current class object being invoked, so you'd have to pass the class parameter in. And you face the issue that this kind of reflection is not first-class in Java. An alternative? Well, factories! Constructors are essentially a kind of static method [1], and it's very desirable to be able to have some sort of generic construction mechanism. The standard design pattern is to have a factory class, which has a method that can actually construct the object in question. Now you can add on to this factory class other methods that can dispatch on the factory class instance--which is effectively the same as class object itself. [1] Okay, internally they're a special nonvirtual method. But given that you need to know the type of the receiver to execute the new opcode, they're more like a static method than an instance method in terms of use. -- Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.java.programmer
csiph-web