Java refers to lib java.lang.String not my java.lang.String - java

I have created a class with the same name and package as the String java class.
package java.lang;
public class String {
public String() {
System.out.println("This is my string ");
}
public void show() {
System.out.println("From show mathod .");
}
}
When I try to invoke this show method it gives error for no such method. It refers to API class. why.?
import java.lang.*;
public class Test {
public static void main(String[] args) {
String str = new String();
str.show();
}
}
I know that I am violating the rule of unique package and class name. But I want to know if I add two jars in my class-path and they have same structure. In such case is there any behaviour defined by Java which class will be loaded.
And why java does not load my class instead of Java API classes? (I also tried this with other api defined classes)
#Please do not give answer like I am violating the rule or work arounds.

Java comes shipped with classes. One of these classes is java.lang.String.
These pre-shipped classes take precedence in the classpath over any class that you might write that have the same package and name.
Whenever you do a new java.lang.String(), regardless if you have a class with the same package and name, the runtime class shipped by Oracle will take precedence.
Since java.lang.String is also a final class, there's no way you will be able to add new methods to it. The best solution is for you to create a new class in a different package or under a different name.

classes can not be redefined after the VM has started and the class has been loaded. As java.lang.String is being used way before your code, it would already be loaded.
I am not sure that you could even achieve this using a byte code enhancement library like javassist

Just tried to write custom ClassLoader to load my class named java.lang.String. Ran out of luck here:
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:658)
at java.lang.ClassLoader.defineClass(ClassLoader.java:794)
at java.lang.ClassLoader.defineClass(ClassLoader.java:643)
at temp.TempLoader.findClass(TempLoader.java:20)
at temp.TempLoader.main(TempLoader.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Offending code in JRE java.lang.ClassLoader:
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " +
name.substring(0, name.lastIndexOf('.')));
}
It would be interesting to see any "pure Java" solution (not involving out-of-JVM changes to runtime) which can workaround this.
You may wonder how JVM itself loads java.* classes? Well, they loaded by so called bootstrap loader, during initialization of JVM instance. I assume, there's no public API to that classloader.

I don't know what you are trying to do exactly, but I can suggest a different approach.
In java String class is final, so, it can't be extended. Create a wrapper class which has your additional methods and a String field.. Now you can define and call show() on your class (You can't do it on the String directly..) If split() is called on your class, then just delegate the call to String class's split().
expose a method getInstance() in your wrapper . Whenever myWrapper.getInstance() is called, call new String() from there..

Related

Is to possible to write and load your own version of core Java classes?

I was asked this question during an interview -"Is to possible to write and load your own version of core Java classes (Like String,Object etc)". I said no but the interviewer wanted to know what checks does Java have to prevent this. To understand this I wrote the below piece of code in eclipse
package java.lang;
public final class String {
public static void main(String[] args) {
String s = new String();
}
}
I was expecting the compilation to fail because Java already has a String class in java.lang package. But the compilation went through and I got the below error when I ran the program --
Error: Main method not found in class java.lang.String, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
Why was the compilation successful considering String is already present in java.lang and how does Java block loading core classes by developers?
javac has to compile the core classes.
There are checks done at runtime to prevent you loading duplicate classes.
You can't load any classes starting with java.. I believe, this was done to stop Microsoft doing naughty incompatible things.
You can't load two classes with the same name with the same class loader instance.
By default the class loader will check the parent loader before loading a class. This one is overridable (with the relevant security permissions).
You can start a JVM with different core classes, though this wll be implementation specific. Up to JDK 8 you could use -Xbootclass/p: selective replace classes.

Why does the whole package structure need to be included in Class.forName()?

I have developed a normal Java project and I am trying to understand the difference between ClassNotFoundException and NoClassDefFoundException. I have found one weird behavior, which is that I need to include the whole package structure when I am calling Class.forName().
See the code below:
package org.com;
public class MainApp {
public static void main(String[] args) {
try {
Class cls = Class.forName("org.com.MainApp");
System.out.println("Class = " + cls.getName());
} catch(ClassNotFoundException ex) {
System.out.println(ex.toString());
}
}
}
If I use Class.forName("MainApp") instead of Class.forName("org.com.MainApp") an exception is thrown.
Can someone please explain the actual reason for this?
Basically, because the contract says so:
className - the fully qualified name of the desired class.
You could very well have two classes named MainApp, in different packages. How would the classloader know which class to load if you omit the fully qualified name (i.e. including the package)?
In other words, it is a design desicion, and in my opinion, a good one.
Class.forName("MainApp") would actually try to load a class named MainApp located in the default package, that is no package name is specified in the class.
Because your class exist in that Package and forName method requires Fully Qualified name
Suppose if java has a AI to identify your classes by specifying only name, what will happend when you specify "Date" ?
Class cls = Class.forName("Date");
Is it need to give you java.util. Date class or java.sql.Date class or any third party library Date class ?
Thats why you need to specify package name to uniquely identify that class
Class.forName has no concept whatsover of your class or where it's called from.
It's a general purpose tool.
For example:
You are the ONLY person in the city called alexander.
You order a package by amazon and say, deliver it to Alexander.
You, from your perspective are the only one alexander in the city, quite easy not?
Now look from the perspective of amazon.. they have no clue where to send it.
The same logic applies to class.forName.
When you compile code, the compiler knows which package you are compiling and which classes you have imported, so when you give it a class name it can check these things to find which fully qualified class name you meant.
However, Class.forName is method on the class Class. All it knows is what you passed it, the class name. It doesn't know the package of the caller, nor what imports you used. Only the fully qualified class name can work.
Simple answer:
Same class may be part of multiple packages and JVM is not sure which class you are want to load.
You may have MainApp class in package1 and package2.
To avoid ambiguity, fully qualified class name is required in Class.forName
e.g.
Class.forName("package1.MainApp")
Class.forName("package2.MainApp")
Notes from documentation page:
public static Class<?> forName(String className)
throws ClassNotFoundException
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
Parameters:
className - the fully qualified name of the desired class.
Returns: the Class object for the class with the specified name.

NoClassDefFoundError

I have an issue where NoClasDefFoundError is being thrown. It puzzles me since I am using interfaces, and no class definition should be available. I have read through some posts which point to Classpath, but I don't believe that to be the issue here (although I may be wrong). I am using NetBeans 6.9.1 IDE.
I have created a sample setup to reproduce the issue. Four projects: Interfaces, Objects, Locator and Consumer. Below you will find the implementations.
At runtime consumer coplains about missing SomeObject implementation, which it should not be aware of since it is accepting interface.
Exception in thread "main"
java.lang.NoClassDefFoundError:
objects/SomeObject
What am I missing?
package interfaces;
public interface ISomeInterface { }
package objects;
import interfaces.ISomeInterface;
public class SomeObject implements ISomeInterface{ }
package locator;
import interfaces.ISomeInterface;
import objects.SomeObject;
public class Locator { public static ISomeInterface LocateImplementation() { return new SomeObject(); }}
package consumer;
import interfaces.ISomeInterface;
import locator.Locator;
public class Main { public static void main(String[] args) { ISomeInterface object = Locator.LocateImplementation(); }}
You can get a NoClassDefFoundError exception with interfaces just as you can with classes. Consider the "Class" in the name of the exception to be the .class file that is generated from compiling a class or interface, not a Java class.
This is saying that the class/interface objects.SomeObject isn't visible on your classpath. Check the location of that .class file and ensure that it's on your classpath - if you're positive it's there, give us some screen shots or something that might help to debug the problem.
Think of NoClassDefFoundError as a runtime linkage problem. JRE loaded one class (or an interface) and it references another class (or an interface), but that referenced class isn't found.
The only way this can happen if you have packaging/classpath issues such that your runtime environment doesn't reflect how things are at build time.
If you are launching this from IDE, make sure that you aren't ignoring any errors and launching anyway. Some classes will not be generated that way.
Usually I run into these problems not when a class is missing, but when there is an error in the static initializers.
Try running your code in a debugger, and set the exception breakpoint to break when any exception is thrown, whether caught or not. I bet you have an uncaught exception in the static initializer for some reason.
In the locateImplementation() method you are returning "new SomeObject()",
JVM needs to have its definition when called. I think it is missing.
You should check if your SomeObject class is in class path because -
Well the JVM will be running the below code -
ISomeInterface object = Locator.LocateImplementation();
and when it does that it will call Locator.LocateImplementation(). This code internally tries to instantiate your SomeObject class which it does not find in the classpath.
So your below understanding
It puzzles me since I am using
interfaces, and no class definition
should be available.
Is not really valid.
Any Interface must be declared inside class
public class Calbacks {
public interface IBaseFragmentInterface {
void NotifyMainActivity();
}
}

In java how do you refer to a class that is in the default package of a third party library?

I have downloaded a third party library and they have classes I need to refer to in the default package? How do I import these classes?
It's not possible directly with the compiler. Sun removed this capability. If something is in the default namespace, everything must be in the default namespace.
However, you can do it using the ClassLoader. Assuming the class is called Thirdparty, and it has a static method call doSomething(), you can execute it like this:
Class clazz = ClassLoader.getSystemClassLoader().loadClass("Thirdparty");
java.lang.reflect.Method method = clazz.getMethod("doSomething");
method.invoke(null);
This is tedious to say the least...
Long ago, sometime before Java 1.5, you used to be able to import Thirdparty; (a class from the unnamed/default namespace), but no longer. See this Java bug report. A bug report asking for a workaround to not being able to use classes from the default namespace suggests to use the JDK 1.3.1 compiler.
To avoid the tedious method.invoke() calls, I adapted the above solution:
Write an interface for the desired functionality in your desired my.package
package my.package;
public interface MyAdaptorInterface{
public void function1();
...
}
Write an adaptor in the default package:
public class MyAdaptor implements my.package.MyAdaptorInterface{
public void function1(){thirdparty.function1();}
...
}
Use ClassLoader/Typecast to access object from my.package
package my.package;
Class clazz = ClassLoader.getSystemClassLoader().loadClass("MyAdaptor");
MyAdaptorInterface myObj = (MyAdaptorInterface)clazz.newInstance();
myObj.function1();

Defining classes in Java files

I have found one error in my Java program:
The public type abc class must be defined in its own class
How can I resolve this error? I am using Eclipse. I am new to Java programming.
Each source file must contain only one public class. A class named ClassName should be in a file named ClassName.java, and only that class should be defined there.
Exceptions to this are anonymous and inner classes, but understanding you are a beginner to Java, that is an advanced topic. For now, keep one class per file.
Answering your addition: it is OK to inherit classes and that's totally fine. This does not matter, each class should still have its own file.
Public top-level classes (i.e. public classes which aren't nested within other classes) have to be defined in a file which matches the classname. So the code for class "Foo" must live in "Foo.java".
From the language specification, section 7.6:
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 rule, which doesn't have to be followed by compilers, is pretty much universally adhered to.
Ok, maybe an example will help.
In file MySuperClass.java:
public class MySuperClass {
// whatever goes here
}
public class MySubClass1 extends MySuperClass {
// compile error: public class MySubClass1 should be in MySubClass1.java
}
class MySubClass2 extends MySuperClass {
// no problem (non-public class does not have to be in a file of the same name)
}
In file MySubClass3.java:
public class MySubClass3 extends MySuperClass {
// no problem (public class in file of the same name)
}
Does that make things clearer?
A public class with the name of "abc" must be in a file called abc.java
You can create a new class an a existing file if it's private, but you should not do this.
Create one file per class.
Eclipse does that for you, if you create a new class.
For programming Java, you have to understand the construct of classes, packages and files. Even if Eclipse helps you, you have to know it for yourself. So start reading Java books or tutorials!

Categories

Resources