For this source code ...
... Eclipse reports the following error:
Only a type can be imported. pkg.a resolves to a package
... while Suns javac compiles it fine.
Similar situation if I try to fully qualify the class pkg.a like this:
Eclipse reports...
pkg.a cannot be resolved to a type
... while Suns javac compiles it fine.
It seems like Eclipse favors interpreting an identifier as a package over a class name, while javac does the exact opposite. So, is it a bug in Eclipse or in javac?
(A reference to the language specification is obviously a plus.)
It is definitely an Eclipse bug:
6.4.2. Obscuring
A simple name may occur in contexts where it may potentially be interpreted as the name of a variable, a type, or a package. In these situations, the rules of §6.5 specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. Thus, it is may sometimes be impossible to refer to a visible type or package declaration via its simple name. We say that such a declaration is obscured.
The clear implication is that it is legal for a class and a package to have the same name. Otherwise, the JLS would say that a class obscuring a package was illegal ... not that the class is used in preference.
Having said that, the only reason you've gotten into this situation is that you've chosen to ignore Java's conventions on naming. Don't expect much sympathy ...
It's a styling convention to give classes a name starting with a capital letter and packages with a lower case letter; that would solve your problem.
Related
I have my own System class with a Test class in the same package which test methods declared in the System class. I also have created a System constructor which takes 3 parameters. When I created a constructor to test the methods in my IDE the program was working fine (I had use java.util.System where I need to use the System. methods) but IDE knew I was referring to my own class when I created the constructor. However, when I trying running my test class from command line it won't even compile:
error: constructor System in class System cannot be applied to given types;
System sys = new System("String1", "String2", 20);
^
required: no arguments
found: String,String,int
reason: actual and formal argument lists differ in length
My guess is that instead of my constructor, the java.util.System constructor (with no parameters) is being invoked which causes the whole program to crash. Does anyone know how to fix it and why is it only happening in command line and not in IDE?
You mention java.util.System, but that's not where the platform's System lives; it lives in java.lang.
This is a problem. Java code acts as if import java.lang.*; is at the top of every file, even if you don't write it. The java language spec says so. So now you get into a fun dilemma:
Given a class named System in the same package, and you star-imported another package that also has a System class in it, which one is chosen if you use an unqualified type reference "System" someplace in the code?
The answer is presumably that whilst the spec is clear on this, few to no java coders care about the answer. They'd rather just.. not get into this bizarro situation. Thus, don't use star imports lightly, and don't name any classes the same as classes in the java.lang package.
If you must know, the order is as follows:
To resolve the type name System into which actual type it is referring to:
Check if there is a named (non-star) import for it: import java.lang.System;
Check if there is a class named System in this source file.
Check if there is a class named System in this package.
Check if there is a class named System in any star-imported package (and therefore, in java.lang as that is always star-imported.
Thus, given that it sounds like your System class is in the same package, that one 'wins'. However, if during a compilation run your non-test source files (your System.java file) is not on the classpath or sourcepath, then instead of the compiler straight up telling you this, instead you get the error you witness.
So, you have 2 problems:
you are not compiling the test classes on the command line correctly. Use a build system.
Don't name classes the same as classes in the lang package; whilst you can make code that works, and the ordering is well defined, it's confusing (hey, it confused you - that's anecdotal evidence right there!) and not idiomatic java. Other folks will have a very hard time reading your code, and you're likely to run into bugs in IDEs and such, because when you're doing weird unique things, odds go way up you run into scenarios nobody thought of and nobody ran into before.
While reading about the multiple inheritance or diamond problem in Java I realized that it is not supported. But I wonder how does Java actually restricts multiple inheritance?
Is there any class to check if the programmer is passing more than one class name after extends keyword or some other way to detect this functionality?
I read few articles but nothing suggest about how exactly Java prevents Multiple inheritance except the one common answer that it throws an error: classname is inheriting multiple classes.
But I wonder how does Java actually restricts multiple inheritance?
It is disallowed at the syntax level. The syntax for a class declaration allows one class name after the extends keyword. And the names in the implements list must be interface names not class names. See Section 8.1 Class Declarations of the JLS. The compiler checks both of these things. Java source code that attempts to declare multiple super-classes will not compile.
At the implementation level, the format for a ".class" file only allows one class to be listed as the super_class; see the ClassFile structure in Section 4.1 of the JVM spec. The identifiers in the interfaces must all refer to interfaces. The various classfile constraints specified in the JVM spec are enforced by the JVM's native classloader.
If you want to see how these restrictions are enforced, you can download an OpenJDK source tree and read the code for yourself. (I don't see the point though. All you really need to know is that the restrictions are strictly enforced and there is no practical way to get around that enforcement.)
If you try to extend more than one class, the compiler will actually complain, and state error: '{' expected. If you are interested in what part of the JDK actually does this, I suggest taking a look at the OpenJDK sources. Source code for the javac parser can be found here.
As a side note, Java disallows multiple inheritance of state, which is what you are referring to. You can still achieve multiple inheritance of behavior through implementing multiple interfaces, though.
Consider the following code:
A.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
#interface A{}
C.java:
import java.util.*;
#A public class C {
public static void main(String[] args){
System.out.println(Arrays.toString(C.class.getAnnotations()));
}
}
Compiling and running works as expected:
$ javac *.java
$ java -cp . C
[#A()]
But then consider this:
$ rm A.class
$ java -cp . C
[]
I would've expected it to throw a ClassNotFoundException, since #A is missing. But instead, it silently drops the annotation.
Is this behaviour documented in the JLS somewhere, or is it a quirk of Sun's JVM? What's the rationale for it?
It seems convenient for things like javax.annotation.Nonnull (which seems like it should've been #Retention(CLASS) anyway), but for many other annotations it seems like it could cause various bad things to happen at runtime.
In the earlier public drafts for JSR-175 (annotations), it was discussed if the compiler and runtime should ignore unknown annotations, to provide a looser coupling between the usage and declaration of annotations. A specific example was the use of applications server specific annotations on an EJB to control the deployment configuration. If the same bean should be deployed on a different application server, it would have been convenient if the runtime simply ignored the unknown annotations instead of raising a NoClassDefFoundError.
Even if the wording is a little bit vague, I assume that the behaviour you are seeing is specified in JLS 13.5.7: "... removing annotations has no effect on the correct linkage of the binary representations of programs in the Java programming language." I interpret this as if annotations are removed (not available at runtime), the program should still link and run and that this implies that the unknown annotations are simply ignored when accessed through reflection.
The first release of Sun's JDK 5 did not implement this correctly, but it was fixed in 1.5.0_06. You can find the relevant bug 6322301 in the bug database, but it does not point to any specifications except claiming that "according to the JSR-175 spec lead, unknown annotations must be ignored by getAnnotations".
Quoting the JLS:
9.6.1.2 Retention Annotations may be present only in the source code, or
they may be present in the binary form
of a class or interface. An annotation
that is present in the binary may or
may not be available at run-time via
the reflective libraries of the Java
platform.
The annotation type
annotation.Retention is used to choose
among the above possibilities. If an
annotation a corresponds to a type T,
and T has a (meta-)annotation m that
corresponds to annotation.Retention,
then:
If m has an element whose value is annotation.RetentionPolicy.SOURCE,
then a Java compiler must ensure that
a is not present in the binary
representation of the class or
interface in which a appears.
If m has an element whose value is annotation.RetentionPolicy.CLASS, or
annotation.RetentionPolicy.RUNTIME a
Java compiler must ensure that a is
represented in the binary
representation of the class or
interface in which a appears, unless m
annotates a local variable
declaration. An annotation on a local
variable declaration is never retained
in the binary representation.
If T does not have a (meta-)annotation
m that corresponds to
annotation.Retention, then a Java
compiler must treat T as if it does
have such a meta-annotation m with an
element whose value is
annotation.RetentionPolicy.CLASS.
So RetentionPolicy.RUNTIME ensures that the annotation is compiled into the binary but an annotation present in the binary doesn't have to be available at runtime
if you actually have code that reads #A and does something with it, the code has a dependency on class A, and it will throw ClassNotFoundException.
if not, i.e. no code cares specificly about #A, then it's arguable that #A doesn't really matter.
As the title already says, I would like to know if it is somehow possible to give a class a different filename in Java with Eclipse ?
Edit: I only want to know if its possible with Eclipse. If you don't know the answer, please resist the urge to respond with condescending answers.
Edit2: It's hilarious what kind of responses I get here. All I wanted to know is if it is possible to have a class with a different filename (and I meant the public class) and nothing else. I thought this is the kind of forum to ask these questions, but the second response I got was already an insult. Is this some kind of taboo question or what is going on ?
Your filename should always match your class name, end of story. Although the JLS doesn't specifically state that it HAS to be done, they leave it up to the implementation of the compiler to make that decision. I'm pretty sure most (if not all) will not allow you to differ from that standard.
The JLS states:
When packages are stored in a file system (§7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:
The type is referred to by code in other compilation units of the package in which the type is declared.
The type is declared public (and therefore is potentially accessible from code in other packages).
This restriction implies that there must be at most one such type per compilation unit. This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package; for example, the source code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket, and the corresponding object code would be found in the file Toad.class in the same directory.
So while you may be able to rename the file itself in eclipse, or your filesystem - you will more than likely hit a compile error.
I don't know why you would like to do that but it is possible if you compile files from command line with help of symbolic links.
Let's say you have class YourClass saved in a file OtherName.java. If you create a symbolic link to that file like this:
UNIX system: (for sure doesn't work on Solaris - other system aren't verified)
ln -s OtherName.java YourClass.java
javac YourClass.java
WINDOWS system: (works on Windows Vista/2008+)
mklink YourClass.java OtherName.java
javac YourClass.java
the compiler finds the type and compilation works...
This solution is not verified on Unix systems, but works for sure on Windows Vista/2008+..
What does Eclipse have with the naming conventions or rules of Java Programming Language?
Eclipse is just an IDE, and if you are working with Java you have to obey its rules.
Lets's say you have X.java file. This means that you can have only one public / abstract / final class named X in this file. There is no limitation on the number of classes and their names and also their nesting relations with each other as far as no more than one class holds the filename as its class name. If a class takes the filename, then it should have one or more of these modifiers: public, static, final. That's the story.
No, the Java a public class and the file must have the same name.
If you try to give the class another name, the compiler will fail with
class YourClass is public, should be declared in a file named YourClass.java
But you can declare additional private classes in a file which contains a public class.
below are the situations where you can have different class name.
1.class is not public class and exists in a java file where atleast one public class is defined
class notpublic{
}
public class PublicClass {
}
2.Class is a InnerClass .
public class PublicClass {
class InnerClass{
}
}
we can declare only one public file in a source file and file name must match the public class name
is there any reason to this restriction....
Well, it's not a compulsory restriction in Java. It's one that the Java Language Specification mentions as an option. From section 7.6 of the JLS:
When packages are stored in a file system (§7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:
The type is referred to by code in other compilation units of the package in which the type is declared.
The type is declared public (and therefore is potentially accessible from code in other packages).
This restriction implies that there must be at most one such type per compilation unit. This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package; for example, the source code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket, and the corresponding object code would be found in the file Toad.class in the same directory.
But basically it's there to encourage you to make your source easier to navigate. If you know the name of a public class, it's usually pretty easy to find the source code for it.
Yes, it's the specification of the Java language...
The reason is, that this is the convention. Also the classloader expects a class in a specific file. You can write your own classloader to avoid this restriction, but there is no good reason to do this. Everyone looking on your code will get confused. ;)
However, you can create "multiple" classes in one file by creating inner classes. I know, its not the same, but usually you should think about more important things than why there is only one class in one file.
It's there so that the compiler can find the source code of dependent classes.
#saravanan. I have executed some simple programs which show that just a single default class(ie a class with no access specifier) having the main method works well in java when u save the file name with the default class name.
To add on to the reason of naming the file with public class name, in a document I went through the details into this state that the JVM looks for the public class (since no restrictions and can be accessible from any where) and also looks for public static void main() in the public class .
This public class acts as the initial class from where the JVM instance for the java application( program) is begun.So when u provide more than one public class in a program the compiler itself stops you by throwing an error.
This is because later you can't confuse the JVM as to which class to be its initial class because only one public class with the public static void main(String args[]) is the initial class for JVM.
HOPE I have helped you in understanding JAVA programming naming better.
simply remember only that class would be public which has the main other files dont be public