开发者

Why do you name the class twice during instantiation in Java?

开发者 https://www.devze.com 2022-12-14 15:34 出处:网络
When you instantiate开发者_运维技巧 an object, why do you specify the class twice? OddEven number = new OddEven();

When you instantiate开发者_运维技巧 an object, why do you specify the class twice?

OddEven number = new OddEven();

Why can't you just say number = new OddEven();? When I declare a string, I only say String once:

String str = "abc";

Actually, my question is not "why do you do it this way" -- obviously, you do it because you have to -- but rather, why did the creators choose to make Java syntax work like this?

My thoughts are:

  1. There is something fundamental to the way Java operates at a low level that necessitates typing the name twice, or
  2. The creators freely choose to do it this way to keep some aspect of the syntax uniform -- declare the type first? Or was it to be more like its predecessors?


Because you can do this:

Superclass x = new Subclass();

The type of the reference can be a superclass of the actual object being declared, so you need to specify both. For example, you can do:

List<String> stringList = new ArrayList<String>();

Your program interacts with objects that implement List, and you don't care about the implementation.,


The reason for the seemingly redundant type name is that you are performing two separate operations, each of which requires you to specify a type.

On the left side, you are declaring a variable (a storage location) with a particular type. On the right side, you are creating a new object with a particular type. The '=' in the middle causes a reference to the new object you created to be placed in the storage location you created.

The types on each side do not have to be the same. This, for example, is legal code:

Object number = new OddEven();

The reason that the keyword String only shows up once in your second example is that the type String is implied on the right hand side since "xxx" is a String constant. It is simply shorthand for:

String string = new String("xxx");


When you write:

OddEven number = new OddEven();

You actually do two things : 1) you declare a variable number of type OddEven and 2) you assign a reference to a new instance of class OddEven. But because a variable can hold any subtype of a type, writing number = new OddEven(); wouldn't be enough for the compiler to know the real type of the number variable. So, you have to declare it too. Java is a strongly typed language, which means that every variable and every expression has a type that is known at compile time. You may want to read the whole Chapter 4. Types, Values, and Variables of the Java Language Specification (JLS) to learn more on this.

Now, when your write:

String str = "abc";

Things are a bit different. Characters enclosed in double quotes, "abc" here, are called a string literal which is already a reference to an instance of String and always refers to the same instance of class String. Quoting the section 3.10.5 String Literals of the JLS:

Each string literal is a reference (§4.3) to an instance (§4.3.1, §12.5) of class String (§4.3.3). String objects have a constant value. String literals-or, more generally, strings that are the values of constant expressions (§15.28)-are "interned" so as to share unique instances, using the method String.intern.

So, String str = "abc"; is certainly not converted into String str = new String("abc"); which is absolutely not equivalent as I've read in some comments and answers. Running the following class:

public class Test {
    public static void main(String[] args) {
        String one = "abc";
        String two = "abc";
        String abc = new String("abc");

        System.out.println(one == two);
        System.out.println(one == abc);
    }
}

Produces the output below:

true
false

And demonstrates that one and two are references to the same instance but that abc is a reference to another instance (i.e. an extra unnecessary object has been created).

Actually, using new String(String) is a inefficient way to construct new strings and should only be used to force a substring to copy to a new underlying character array, as in

String tiny = new String(monster.substring(10,20))


Think of 'OddEven number' as defining the Object and 'new OddEven();' as filling the object.

I'm not going to get into detail about superclasses and subclasses because other people have explained it already.


When you say String name = "foo", internally Java compiler creates a String object with the value "foo" and it assigns its reference to name variable. So, here instead of creating a new String object, we are assigning a reference to the other String object.

Btw, the compiler anyway creates "foo" for us. It first looks in String Pool, if it not exists, only then it creats "foo". Otherwise, Compiler returns a reference from String pool. This is some optimization that Java compiler performs internally.

String name = "foo" is simlar to OddEvenNumber oddEven = anotherOddEvenObject;


Array example:

declaration and initialization - when you know the length of the array:

int[] numberArray = new int[10];

declaration then initialization - when you don’t know the length of the array yet and might get it from a method or user input

int[] numberArray;
int length = 10; // let’s say we got this from the user
numberArray = new int[length];

Initialization only - when you don’t need to reuse:

return new int[10];


First OddEven is the type, second is the instance. It need not be even OddEven, it could be any subclass of OddEven. It does not mean you have type it twice. Any IDE have code templates where you have to type the name only once.


The first declaration is the type of variable you want to use in the scope you have, in this case it is OddEven, the second declaration is the constructor to use for instantiating (and in this case initializing) the reference.

You could have said INumberInstance = new OddEven(), where INumberInstance is some class which OddEven can be cast to (like a super of OddEven for instance).


The way to create a new object in java is:

Class_name reference_variable = new Class_name(param_if_any);

But the string class is an exception.

You can create a new string object as

String s = "abc";

or

String s = new String("abc");


Further to what Jim said, Java is a statically typed language. That means that every varable has a type that is know at compile time.

For instance:

public class A
{
    public void foo() { }
}

public class B
{
    public void foo() { }
}

public class Main
{
    public static void main(final String[] argv)
    {
        A a = new A();
        B b = new B();

        a.foo();
        b.foo();
    }
}

the compiler looks at "a.foo()" and "b.foo()" and checks to see that a is of type A and A has a method called "foo" that takes no arguments. The compiler does the same for "b.foo()".

If you could write main like this:

public class Main
{
    public static void main(final String[] argv)
    {
        a = new A(); // in Java you would really do Object a = new A();
        b = new B(); // in Java you would really do Object b = new B();

        a.foo();
        b.foo();
    }
}

then the compiler could not do that verification and it would have to happen at runtime.


The designers of Java did not have to make the syntax redundant. Scala is another language using the JVM, and it's also statically typed. Scala uses type inferencing to cut out verbosity. For instance here's a declaration of a variable of type MyPair called x. MyPair associates two variables with each other. It's a generic class, so you can specify that the first variable have type Int and the second the type String:

var x: MyPair[Int, String] = new MyPair[Int, String](1, "scala")

Scala type inferencing lets you remove the redundant type declaration:

var x = new MyPair[Int, String](1, "scala")

And Scala even infers types based on the constructor arguments, so you can write it this way:

var x = new MyPair(1, "scala")


Consider the following example,

We can specify the object type as follows,

List<String> abc;

In method1(), if you want to use array list which suits the best for it requirements then we can instantiate like as follows,

abc = new ArrayList<String>();

In method2(), if you want to use Linked array list which suits best for it requirement then we can instantiate like as follows,

abc = new LinkedList<String>();

So, the idea is that we can specify the type of "SuperClass" and instantiate with whatever subclass suitable for different requirements like "LinkedList" and "ArrayList" in the appropriate operation dynamically.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号