inheriting a main method

R

Ross

I would like to write a base class from which child classes inherit a
public static void main( String args[] ) method.

As readers can probably guess, but problem is that the main method
doesn't know which class to create to start the program running.

The parent class is called Game. I can't write a method:

public static void main( String args[] )
{
Game g = new Game();
g.setVisible( true );
}

as it runs the base class.

At present I have a method (simplified, from memory) which takes the
name of the class as a runtime argument. E.g.

public static void main( String args[] ) throws Exception
{
Class c = Class.forName( args[0] );
Game g = (Game) c.newInstance();
g.setVisible( true );
}

This works, but requires the name of the class to be given as an
argument. If I could find out the name of the class that had been
executed, then I could solve this problem. But I've looked in the
System class properties, I've looked in Runtime, and I haven't found
anything.

Is there a solution to this problem? I would like the solution to be
cross-platform.
 
R

Roedy Green

I would like to write a base class from which child classes inherit a
public static void main( String args[] ) method.

You naturally inherit all static methods, including main.

You can specify which generation you want by prefixing the class name.

e.g. Grandma.main Mom.main Me.main

If there is no Me.main, you can use Me.main to get an Mom.main.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"The telephone is the greatest single enemy of scholarship; for what our intellectual forebears used to inscribe in ink now goes once over a wire into permanent oblivion."
~ Dr. Stephen Jay Gould (born: 1941-09-10 died: 2002-05-02 at age: 60)
 
A

Andreas Leitgeb

Roedy Green said:
I would like to write a base class from which child classes inherit a
public static void main( String args[] ) method.
You naturally inherit all static methods, including main.
You can specify which generation you want by prefixing the class name.

e.g. Grandma.main Mom.main Me.main
If there is no Me.main, you can use Me.main to get an Mom.main.

The real question was (as far as I understood it):

Can the implementation of Mom.main() find out, whether the user
used "Mom" or "Me" as startup class? Or perhaps even "Brother"
or "Sister", which for the sake of this example also do not have
their own main() but fall back to Mummy's?

I don't know any way, and I doubt there even is one, but can't say
for sure. Perhaps Java can be asked for the startup-class directly?
 
A

Alessio Stalla

Roedy Green said:
I would like to write a base class from which child classes inherit a
public static void main( String args[] ) method.
You naturally inherit all static methods, including main.
You can specify which generation you want by prefixing the class name.
e.g. Grandma.main  Mom.main Me.main
If there is no Me.main, you can use Me.main to get an Mom.main.

The real question was (as far as I understood it):

Can the implementation of Mom.main() find out, whether the user
used "Mom" or "Me" as startup class?  Or perhaps even "Brother"
or "Sister", which for the sake of this example also do not have
their own main() but fall back to Mummy's?

The real answer is: even if it can, it shouldn't. The OP should really
refactor the code. If a custom launch protocol is desired, write it
explicitly. Something as:

java my.own.Game -game PacMan
(searches for class PacMan in default package my.own.games and invokes
main() or whatever)

java my.own.Game -game org.foobar.FooTetris
(searches for fully qualified class org.foobar.FooTetris and does as
above)

then if that's too verbose you can hide it in a (platform specific)
shell script.

Alessio
 
R

Ross

Thanks, but that doesn't quite work as intended. I have written two
classes:

public class Test
{
public static void main( String args[] )
{
Thread mainThread = Thread.currentThread();
StackTraceElement[] currentStack = mainThread.getStackTrace();
StackTraceElement mainStackElement = currentStack
[ currentStack.length - 1 ];

System.out.println( "My main class is " +
mainStackElement.getClassName() );
}
}

That works fine if I run it, and reports the class as "Test". But I
then create a child class.

public class Test2 extends Test
{
}

If I then run:

$ java Test2

I get the output:

My main class is Test

When what I want is:

My main class is Test2

Any ideas on how to find out the name of the executed class rather
than the ancestor class which has the main method?
 
R

Ross

I could probably solve the problem if I could find a list of the
classes that are currently loaded. As only one of them will be an
instance of "Game", apart from "Game" (my parent class) itself. But
looking through the classloader interface, I can't seem to find that
out either.
 
R

Ross

Ow. Don't do that. For one thing, I don't think there _is_ any way
to retrieve the name of the class mentioned on the command line
in this case. More importantly, it's bad design.

I'd recommend you make an inherited business method, then write
explicit main methods for all the classes that will use it (There
can't be _that_ many of them, and it make it a lot easier to
understand what's happening.)

Something like this:

public abstract class BaseClass {
protected void doStuff( String[] args ) {
// Do whatever you're supposed to do
}

}

public class SubClass extends BaseClass {
public static void main( String[] args ) {
BaseClass myFoo = new SubClass( );
myFoo.doStuff( args );
}

}

If you have common initialization that needs to be done, use an
inherited initialization method as well:

public static void main( String[] args ) {
BaseClass myFoo = new SubClass( );
myFoo.initialize( args );
myFoo.doStuff( );
}

Unfortunately, I need to do this. The parent class is going to be
subclassed by young children, first experimental subject being a nine
year old. I have to kick out the main class, but still have it
runnable. Fundamentally, you can't teach advanced programming
languages with sophisticated structures to young children, or at least
most young children. I'm sure there are some prodigies out there.
Previously when I've done this before, I've created bespoke
programming languages with bespoke IDEs. But the whole point of what
I'm trying now is to see whether Object Orientated Programming can be
leveraged to produce a LOGO style language (and execution environment)
while the code being written is actually proper Java, just extending a
prewritten class.

The alternative is to modify the IDE that will be used to supply the
name of the class as the first argument to the running program. I
don't particularly want to modify the IDE, as that means that the IDE
would become a necessary part of the environment, but it is currently
the best solution, and I don't appear to be finding anything better
than that.

Thanks for all for the comments and ideas.
 
A

Alessio Stalla

I could probably solve the problem if I could find a list of the
classes that are currently loaded. As only one of them will be an
instance of "Game", apart from "Game" (my parent class) itself. But
looking through the classloader interface, I can't seem to find that
out either.

If only one game at a time can be loaded (this wasn't apparent from
your first post), you can use a factory to create it. E.g. you can use
the standard service provider machinery: <http://java.sun.com/j2se/1.3/
docs/guide/jar/jar.html#Service%20Provider> or a custom solution.

hth,
Alessio
 
R

Ross

I'd recommend you make an inherited business method, then write
explicit main methods for all the classes that will use it (There
can't be _that_ many of them, and it make it a lot easier to
understand what's happening.)

But, I want to deliver a system where the end user will make up their
own classes. Hence i can't pre-write methods without constraining the
end user to a relatively short list of possible class names.
 
M

Mike Schilling

If I understand the problem, the user runs

java classname

where classname has a superclass that defines the main(String[])
method, and you want it to figure out what "classname" is. This can't
be done.

However, if you change the command to

java mainclass classname

where classname, instead of subclassing mainclass, implements some
known interface, it becomes trivial. (mainclass.main() calls
class.forName().newInstance() on its argument, but you knew that.)
 
M

markspace

Ross said:
Previously when I've done this before, I've created bespoke
programming languages with bespoke IDEs. But the whole point of what
I'm trying now is to see whether Object Orientated Programming can be


I'm still more than a little confused about what you want the final
result to look like. Do you want a command line? An IDE? Something
different?

The alternative is to modify the IDE that will be used to supply the
name of the class as the first argument to the running program.


This could be done pretty easily in NetBeans by setting the default
template for a new class, and turning on code folding. The kids will
not see the boilerplate code supplied by the IDE within the code folds.

You also might be able to use a custom Ant script. I'm not sure about
generating one on a new project though.
 
D

Daniel Pitts

Ross said:
I could probably solve the problem if I could find a list of the
classes that are currently loaded. As only one of them will be an
instance of "Game", apart from "Game" (my parent class) itself. But
looking through the classloader interface, I can't seem to find that
out either.
You could also have your main in a *different* class than the one being
subclassed, and then pass the "Game Class Name" as a separate query
argument.

Also, It could be a requirement that your Game class does *not* supply a
main method, but instead make the "main method" easy to write.
 
A

Arne Vajhøj

Andreas said:
Roedy Green said:
I would like to write a base class from which child classes inherit a
public static void main( String args[] ) method.
You naturally inherit all static methods, including main.
You can specify which generation you want by prefixing the class name.

e.g. Grandma.main Mom.main Me.main
If there is no Me.main, you can use Me.main to get an Mom.main.

The real question was (as far as I understood it):

Can the implementation of Mom.main() find out, whether the user
used "Mom" or "Me" as startup class? Or perhaps even "Brother"
or "Sister", which for the sake of this example also do not have
their own main() but fall back to Mummy's?

I don't know any way, and I doubt there even is one, but can't say
for sure. Perhaps Java can be asked for the startup-class directly?

If we can assume that Java version >= 1.5, main thread has
thread id 1 and max. stack depth is 1000:

StackTraceElement[] ste =
ManagementFactory.getThreadMXBean().getThreadInfo(1, 1000).getStackTrace();
String clznam = ste[ste.length-1].getClassName();

Arne
 
M

Mike Schilling

Arne said:
Andreas said:
Roedy Green said:
I would like to write a base class from which child classes
inherit a public static void main( String args[] ) method.
You naturally inherit all static methods, including main.
You can specify which generation you want by prefixing the class
name. e.g. Grandma.main Mom.main Me.main
If there is no Me.main, you can use Me.main to get an Mom.main.

The real question was (as far as I understood it):

Can the implementation of Mom.main() find out, whether the user
used "Mom" or "Me" as startup class? Or perhaps even "Brother"
or "Sister", which for the sake of this example also do not have
their own main() but fall back to Mummy's?

I don't know any way, and I doubt there even is one, but can't say
for sure. Perhaps Java can be asked for the startup-class directly?

If we can assume that Java version >= 1.5, main thread has
thread id 1 and max. stack depth is 1000:

StackTraceElement[] ste =
ManagementFactory.getThreadMXBean().getThreadInfo(1,
1000).getStackTrace(); String clznam =
ste[ste.length-1].getClassName();

Is that really going to give you the class mentioned in the command line
rather than the class which defines the static main() method?
 
A

Arne Vajhøj

Mike said:
Arne said:
Andreas said:
I would like to write a base class from which child classes
inherit a public static void main( String args[] ) method.
You naturally inherit all static methods, including main.
You can specify which generation you want by prefixing the class
name. e.g. Grandma.main Mom.main Me.main
If there is no Me.main, you can use Me.main to get an Mom.main.
The real question was (as far as I understood it):

Can the implementation of Mom.main() find out, whether the user
used "Mom" or "Me" as startup class? Or perhaps even "Brother"
or "Sister", which for the sake of this example also do not have
their own main() but fall back to Mummy's?

I don't know any way, and I doubt there even is one, but can't say
for sure. Perhaps Java can be asked for the startup-class directly?
If we can assume that Java version >= 1.5, main thread has
thread id 1 and max. stack depth is 1000:

StackTraceElement[] ste =
ManagementFactory.getThreadMXBean().getThreadInfo(1,
1000).getStackTrace(); String clznam =
ste[ste.length-1].getClassName();

Is that really going to give you the class mentioned in the command line
rather than the class which defines the static main() method?

You are correct. It returns the parent class where main is
defined.

Arne
 
M

Mike Schilling

Arne said:
If we can assume that Java version >= 1.5, main thread has
thread id 1 and max. stack depth is 1000:

StackTraceElement[] ste =
ManagementFactory.getThreadMXBean().getThreadInfo(1,
1000).getStackTrace(); String clznam =
ste[ste.length-1].getClassName();

Is that really going to give you the class mentioned in the command
line rather than the class which defines the static main() method?

You are correct. It returns the parent class where main is
defined.

Right. My strong impression is that trying to figure out which subclass was
mentioned in the command line is simply hopeless (or at best extremely
non-portable) and that, accordingly, the OP should figure out some other way
of doing things. Fortunately, there are dozens of them.
 
M

Mike Amling

Ross said:
I could probably solve the problem if I could find a list of the
classes that are currently loaded. As only one of them will be an
instance of "Game", apart from "Game" (my parent class) itself. But
looking through the classloader interface, I can't seem to find that
out either.

Your students are already compiling their code with some boilerplate,
namely

class Mine extends Game {
....
}

Could you change that boilerplate to invoke a constructor in Game via an
implicit super(), and have the Game constructors leave what you need in
one of Game's static variables where Game.main can find it?

class Mine extends Game {
static {new Mine();}
....
}

--Mike Amling
 
R

Ross

If we can assume that Java version >= 1.5, main thread has
thread id 1 and max. stack depth is 1000:

StackTraceElement[] ste =
ManagementFactory.getThreadMXBean().getThreadInfo(1, 1000).getStackTrace();
String clznam = ste[ste.length-1].getClassName();

Arne

That doesn't work, it always gives the name of the class where main is
declared, not the subclass.
 
R

Ross

Could you change that boilerplate to invoke a constructor in Game via an
implicit super(), and have the Game constructors leave what you need in
one of Game's static variables where Game.main can find it?

class Mine extends Game {
static {new Mine();}
...

}


I could do that, but I think it's more confusing than what I'm going
now.

I've thought about this a bit, and had one go at getting the child to
program in the language. The biggest problem was forgetting to put
semicolons after commands. Because while "proper java" is being
written, methods from the Game class are being used that makes it look
like a "Logo" like language. Because what is being written is limited,
it will be easy to write code into the IDE that looks for common
errors and gives human-like advice. Hence, I'll modify the IDE anyhow,
and making my initial solution work (give the name of the class as an
argument) is easy.

The IDE I'm using is a very basic IDE written by a colleague of mine
at work. I have all the source code.
 
A

Arne Vajhøj

Ross said:
If we can assume that Java version >= 1.5, main thread has
thread id 1 and max. stack depth is 1000:

StackTraceElement[] ste =
ManagementFactory.getThreadMXBean().getThreadInfo(1, 1000).getStackTrace();
String clznam = ste[ste.length-1].getClassName();

That doesn't work, it always gives the name of the class where main is
declared, not the subclass.

True.

Mike Schilling already pointed that out.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,699
Latest member
AnneRosen

Latest Threads

Top