views:

164

answers:

4

I jsut learned that

A class may be declared with the modifier public, in which case that class is visible to all classes everywhere. If a class has no modifier (the default, also known as package-private), it is visible only within its own package.

This is a clear statement. But this information interfere with my understanding of importing of packages (which easily can be wrong). I thought that importing a package I make classes from the imported package visible to the importing class.

So, how does it work? Are public classes visible to all classes everywhere under condition that the package containing the public class is imported? Or there is not such a condition? What about the package-private classes? They are invisible no mater if the containing package was imported or not?

ADDED: It seems to me that I got 2 answers which are marked as good (up-voted) and which contradict eachother.

A: 

If you want to use class A from class B, and class B is not in the same package with class A, you must import class B, even if the class B is public.

If public classes didn't need to be imported, there could be no way of declaring two classes with the same name.

Erkan Haspulat
And if class B is package-private it may only be used in the same package. You must also import inner classes, even when they are in the same package.
Pindatjuh
Just to be sure. If a class A is "package-private" I will be unable to use it from class B even with the import statement. Right?
Roman
Hmmm... In another answer it is written that "import" does not change the visibility. So, I have 2 answers which contradicts with each other.
Roman
@Roman, that's right. Because there will be no package to import from class B. But if both classes are package-private, then they will be visible to each other.
Erkan Haspulat
Import statement does **not** change the visibility of the **imported** class, that's true. I can't see any contradiction in my answer with this statement?
Erkan Haspulat
@Erkan H, you say that I must import a package B from the package A if I want to use public classes from package B in the package A. In other words, classes from package B are invisible to package A untill I import package B. Another answer states that in the package A I can use classes from package B even without importing (I just need to use full name of classes (including names of packages)).
Roman
This is demonstrably rubbish. An import statement is just compile-time *sugar* so that you do not have to refer to the fully-qualified class name in each type declaration. You can write classes with no import statements at all
oxbow_lakes
@Roman, and that other answer is also true. Let me put it this way. If you want to use some class X, you should be able to see it right? There are ways of doing this, one of them is importing them at the beginning of your .java file. The other way, is to see them through their full name, but that is just another way of importing. Using the import statement is cleaner, more readable. These both answers imply the **very same** thing.
Erkan Haspulat
@Erkan -your answer is wrong because you state that an import statement is necessary when using classes from a separate package. That is just not true and is why people are downvoting your answer
oxbow_lakes
@oxbox_lakes, I didn't state that an import statemement is *necesarry*, I stated that a class should be imported(should be somehow visible) to be used. I don't think that my answer is wrong, but I agree that it might be misunderstood.
Erkan Haspulat
@Erkan, I see what you mean. I think that misunderstanding come from ambiguousity of word "visible". We just use different definition of "visible".
Roman
+5  A: 

Importing a class doesn't change its visibility in any way. Importing a class to another class is more or less just a way to make your source code readable so you don't have to put in fully qualified class all the time. For example this class

import java.util.*;

class ImportTests {
    private Collection collection;
}

compiles to the same code that this class would

class ImportTests {
    private java.util.Collection collection;
}

The import statement in the first class doesn't change the visibility of Collection or any other class inside the java.util package it just makes it so the ImportTests class can reference Collection without the fully qualified name.

Yanamon
Well, it seems to me that your answer contradicts with another answer. You say that import does not change the visibility and in another answer to my question it is written that I "must import" to be able to use a pablic class from another package.
Roman
Yes, and this answer is correct, see http://java.sun.com/docs/books/tutorial/java/package/usepkgs.html
meriton
Your example is not quite correct. In the first snippit, if there are 2 classes named Collection, then the code get the first class that is on the classpath. In the second example, it will always get a class in a package named java.util.Collection.
Milhous
@Roman - that's because the other answer is wrong
oxbow_lakes
It is not necessary to use any imports in order reference a public class in another package. As seen in my second example a class can directly reference another class by using its fully qualified name without an import. You could write an entire class this way, although this class would be needlessly long and probably unreadable.
Yanamon
@Milhous - the "first class on the classpath"? What on earth are you on about?
oxbow_lakes
@oxbox_lakes, does using the full name of a class without the import statement, avoids the *actual* import?
Erkan Haspulat
@Milhous. That is not the case, if you have imported 2 packages that both have a class with the same name then you cannot reference that class name without its package name as it is ambiguous, and that is a compile error not just a best practice.
Yanamon
A: 

You do not need to import a path or a class to make it visible.

To make classes or paths visible, you have to specify at classpath declaration during compilation or execution.

"import" directive ("using" directive in C#) merely helps us to be lazy.

If you have classes

why.does.the.sun.go.on.Shining.java,
rather.be.ahammer.thana.Nail.java,

you could always refer them with their full paths without importing them:

public java.util.Hashtable<rather.be.ahammer.thana.Nail> bornFree(
 java.lang.String shiningKey,
 why.does.the.sun.go.on.Shining shiningPath){

 rather.be.ahammer.thana.Nail nailed =
   new rather.be.ahammer.thana.Nail(shiningPath);

 java.util.Hashtable<rather.be.ahammer.thana.Nail> nailedHash =
   new java.util.Hashtable<rather.be.ahammer.thana.Nail>();
 nailedHash.put(shiningKey, nailed);

 return nailedHash;
}

However, laziness being the virtue of creativity, I would rather do

import java.util.Hashtable;
import why.does.the.sun.go.on.Shining.java;
import rather.be.ahammer.thana.Nail.java;

public Hashtable<Nail> bornFree(
 String shiningKey,
 Shining shiningPath){

 Nail nailed =
   new Nail(shiningPath);

 HashTable<Nail> nailedHash =
   new Hashtable<Nail>();
 nailedHash.put(shiningKey, nailed);

 return nailedHash;
}

Which, you probably have already realised.

1 - The question would then be,

if there are two classes of the same name but different namespace, which would be used by the compiler?

import java.util.Date;
import java.sql.Date;

The compiler would complain with error message - conflicting classes for Date
and you would not be able to compile successfully.

So you have to import one of them and use the other with its full path.

In C# we could import

using Dayhawk = hello.day.Hawk;
using Nitehawk = hello.nite.Hawk;

So that we could do,

DayHawk dhawk = new DayHawk(new NiteHawk());

However, either as always, the java authoritarians are either to shy/proud to allow themselves to allow java immitate Microsoft or that Microsoft has a patent on such form of import.

2 - The second question would be,

if we had a class

atlantic.salmon.are.trouts.String.java

Then you did an import

import atlantic.salmon.are.trouts.String;

And when you declare

String salmon = new String();

which String would be used? java.lang.String or atlantic.salmon.are.trouts.String?

The compiler would pick and obey the import statement and use atlantic.salmon.are.trouts.String.

3 - the third issue,

private, protected, public visibility modifiers and default visibility are not to be confused with the import directive at all. Nothing to do except being in the same language.

  • private references are visible only within the same file.
  • protected references are visible only within the same namespace packages or by an extension class.
  • public references are visible to all.
  • Undeclared, i.e. default, references are visible only within the same namespace packages.

Import directive does not change these behaviours at all.

In conclusion,

  • The import directive is merely for the continuance of the virtue of laziness.
  • The import directive is not for the purpose of making classes visible or changing the visibility of their contents.
  • The classpath argument is for making classes visible to the whole project.
  • Noting else can change the behaviour of visibility modifiers in a Java compilation.
Blessed Geek
wall of text does not add anything :(
Jorn
This person is a beginner and you can read from the question that the person needs to understand the underlying issues before understanding the roles between access modifiers and import directive.
Blessed Geek
A: 

I have two packages A and C. A has a class named Random in it. My code here compiles fine, and the random is from A and not from java.util. The java.util import gives me a warning in eclipse that the import is unused.

package C;

import A.Random;
import java.util.*;

public class C
{
public static void main(String[] args)
    {
        Random b = new Random();
    }
}

Here is another example of the hiding of classes.

package C;
import java.util.*;
public class C
{
public static void main(String[] args)
    {
        Random b = new Random();
        System.out.println(b.nextDouble());
    }
}

Here is my Random class.

package C;
import java.util.Scanner;

public class Random 
{
private static final long serialVersionUID = 2632389638401709212L;

Scanner s;

public Random()
    {
        super();
        s = new Scanner(System.in);

    }
public double nextDouble()
    {

        System.out.println("Enter your own random number");
        return Double.parseDouble(s.nextLine());            
    }
}

When I run the C main method I get...

Enter your own random number
1
1.0
Milhous
Yes, if you explicitly import a package, that takes precedence over a wildcard import and is therefore not considered ambiguous. However, two or more explicit imports of the same name OR a reference to a name that is brought in via two or more wildcard imports is ambiguous and therefore a compile error, just as Yanamon said ("if you have imported two packages" = wildcard imports, not explicit).
Joe Carnahan