This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Java pass by reference issue
In my codes below, methodA will be called, which then delegates a call to methodB, in doing so, methodB assigns the input parameter with String literal "bbb", however, back at methodA, the string literal was not there, which section of the JLS defines this behavior?
package sg.java.test2;
public class TestApple {
public static void main(String args[]){
methodA();
}
public static void methodA(){
String a = null;
methodB(a);
System.out.println(a);
}
public static void methodB(String a){
a = new String("bbb");
}
}
this is a pass by value vs pass by reference issue. Java is pass by value ONLY. When you call
methodB(a)
the reference a gets copied; in the context of methodB, a is a different variable that has the same value as in methodA. So when you change it in methodB, a in methodA still points to the original String.
Another issue that comes into play here is that Strings are immutable, so you can't change the value of a String once it is set. From the docs.
Strings are constant; their values cannot be changed after they are
created.
What you could do is
a = methodB();
and return "bbb" in methodB. There is no reason to pass a in because you are not operating on it; I think you were only doing it to try to change a in the context that calls methodB, which you cannot do.
Finally, the relevant part of the JLS is 8.4.1, which says
When the method or constructor is invoked (ยง15.12), the values of the
actual argument expressions initialize newly created parameter
variables, each of the declared Type, before execution of the body of
the method or constructor. The Identifier that appears in the
DeclaratorId may be used as a simple name in the body of the method or
constructor to refer to the formal parameter.
Java is pass by value, not pass by reference.
The method signature is shorthand for this:
methodB() {
String a = arguments[0];
i.e. it is a difference reference. When you assign to 'a', you are assigning to the reference 'a' created as part of the method signature, not to the 'a' you declared in the code block that contained the call to methodB().
You can modify the value if it is an object, however.
class MyObj {
String prop;
public MyObj(String s) { prop = s; }
public MyObj() { }
}
public void methodB(MyObj o) {
o.prop = "foo";
}
public void methodA() {
MyObj a = new MyObj();
System.out.println(a.prop); // null
methodB(a);
System.out.println(a.prop); // foo
}
Related
I'm struggling to see why the following code compiles:
public class MethodRefs {
public static void main(String[] args) {
Function<MethodRefs, String> f;
f = MethodRefs::getValueStatic;
f = MethodRefs::getValue;
}
public static String getValueStatic(MethodRefs smt) {
return smt.getValue();
}
public String getValue() {
return "4";
}
}
I can see why the first assignment is valid - getValueStatic obviously matches the specified Function type (it accepts a MethodRefs object and returns a String), but the second one baffles me - the getValue method accepts no arguments, so why is it still valid to assign it to f?
The second one
f = MethodRefs::getValue;
is the same as
f = (MethodRefs m) -> m.getValue();
For non-static methods there is always an implicit argument which is represented as this in the callee.
NOTE: The implementation is slightly different at the byte code level but it does the same thing.
Lets flesh it out a bit:
import java.util.function.Function;
public class MethodRefs {
public static void main(String[] args) {
Function<MethodRefs, String> f;
final MethodRefs ref = new MethodRefs();
f = MethodRefs::getValueStatic;
f.apply(ref);
//is equivalent to
MethodRefs.getValueStatic(ref);
f = MethodRefs::getValue;
f.apply(ref);
//is now equivalent to
ref.getValue();
}
public static String getValueStatic(MethodRefs smt) {
return smt.getValue();
}
public String getValue() {
return "4";
}
}
A non-static method essentially takes its this reference as a special kind of argument. Normally that argument is written in a special way (before the method name, instead of within the parentheses after it), but the concept is the same. The getValue method takes a MethodRefs object (its this) and returns a string, so it's compatible with the Function<MethodRefs, String> interface.
In the Java Tutorial it is explained that there are 4 different types of method references:
reference to a static method
reference to an instance method of a particular object
reference to an instance method of an arbitrary object of a particular type
reference to a constructor
Your case is #3, meaning that when you have an instance of MethodRef i.e. ref, calling apply on your function f will be equivalent to String s = ref.getValue().
For non-static methods, the type of this is considered implicitly to be the first argument type. Since it's of type MethodRefs, the types check out.
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
So as far as I know, in java you can't access objects directly, you only have the pointer to it. So for example I have this code:
public class App {
public App() {
Thing t = null;
doStuff(t);
System.out.println(t);
}
public void doStuff(Thing a) {
a = new Thing();
}
public static void main(String[] args) {
new App();
}
}
class Thing { }
And the output is null. Why? I've passed the pointer to a method which gave it a new Thing instance to point to. Is it because it's a new pointer? Also how can I resolve it without returning anything from doStuff()?
You have references not pointers, and a method cannot update the callers reference without an assignment in the caller - so this
public App() {
Thing t = null;
doStuff(t);
System.out.println(t);
}
public void doStuff(Thing a) {
a = new Thing();
}
Would work if you did,
public App() {
Thing t = null;
t = doStuff(t);
System.out.println(t);
}
public Thing doStuff(Thing a) {
a = new Thing();
return a;
}
This is because Java works by pass by value of Object references and not pass by reference of an Object ,even if the reference is an Object,it still gets passed by the value of reference.So you always work with new references
Refer:http://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html
Declaring a Variable to Refer to an Object
Previously, you learned that to declare a variable, you write:
type name; This notifies the compiler that you will use name to refer
to data whose type is type. With a primitive variable, this
declaration also reserves the proper amount of memory for the
variable.
You can also declare a reference variable on its own line. For
example:
Point originOne; If you declare originOne like this, its value will be
undetermined until an object is actually created and assigned to it.
Simply declaring a reference variable does not create an object. For
that, you need to use the new operator, as described in the next
section. You must assign an object to originOne before you use it in
your code. Otherwise, you will get a compiler error.
A variable in this state, which currently references no object, can be
illustrated as follows (the variable name, originOne, plus a reference
pointing to nothing):
OK, the first question in this "series" was this one.
Now, here is another case:
Arrays.asList("hello", "world").stream().forEach(System.out::println);
This compiles, and works...
OK, in the last question, static methods from a class were used.
But now this is different: System.out is a static field of System, yes; it is also a PrintStream, and a PrintStream has a println() method which happens to match the signature of a Consumer in this case, and a Consumer is what forEach() expects.
So I tried this...
public final class Main
{
public static void main(final String... args)
{
Arrays.asList(23, 2389, 19).stream().forEach(new Main()::meh);
}
// Matches the signature of a Consumer<? super Integer>...
public void meh(final Integer ignored)
{
System.out.println("meh");
}
}
And it works!
This is quite a different scope here, since I initiate a new instance and can use a method reference right after this instance is constructed!
So, is a method reference really any method which obeys the signature? What are the limits? Are there any cases where one can build a "#FunctionalInterface compatible" method which cannot be used in a #FunctionalInterface?
The syntax of method references is defined in JLS #15.13. In particular it can be of the form:
Primary :: [TypeArguments] Identifier
Where Primary can be, among other things, a:
ClassInstanceCreationExpression
so yes, your syntax is correct. A few other interesting examples:
this::someInstanceMethod // (...) -> this.someInstanceMethod(...)
"123"::equals // (s) -> "123".equals(s)
(b ? "123" : "456")::equals // where b is a boolean
array[1]::length // (String[] array) -> array[1].length()
String[]::new // i -> new String[i]
a.b()::c // (...) -> a.b().c(...)
By the way, since you mention static methods, it is interesting to note that you can't create a static method reference from an instance:
class Static { static void m() {} }
Static s = new Static();
s.m(); //compiles
someStream.forEach(s::m); //does not compile
someStream.forEach(Static::m); //that's ok
From the State of Lambda
Kinds of method references
There are several different kinds of method references, each with
slightly different syntax:
A static method (ClassName::methName)
An instance method of a particular object (instanceRef::methName)
A super method of a particular object (super::methName)
An instance method of an arbitrary object of a particular type (ClassName::methName)
A class constructor reference (ClassName::new)
An array constructor reference (TypeName[]::new)
Saying this:
something(new Main()::meh);
Is approximately equivalent to saying this:
Main x = new Main();
something(() -> x.meh());
Or this:
final Main x = new Main();
something(new Whatever() {
public void meh(Integer ignored) {
x.meh();
}
}
The new instance is "captured" and used in the new lambda instance which was implicitly created from the method handle.
This question already has answers here:
Java method dispatch with null argument
(4 answers)
Understanding which constructor is chosen and why
(4 answers)
Closed 9 years ago.
When I run this code it prints String. My question is why there is no compile time error?
Default value of Object and as well as String is null. Then why not compiler says Reference to method1 is ambiguous.
public class Test11
{
public static void method1(Object obj) {
System.out.println("Object");
}
public static void method1(String str) {
System.out.println("String");
}
public static void main(String[] arr ) {
method1(null);
}
}
From this answer:
There, you will notice that this is a compile-time task. The JLS says in subsection 15.12.2:
This step uses the name of the method and the types of the argument expressions to locate methods that are both accessible and applicable There may be more than one such method, in which case the most specific one is chosen.
The compiler will look at all the possible overloads of the method that could match the parameters you pass. If one of them is more specific than all the others then it will be chosen, it's only considered ambiguous if there is no single most specific overload.
In your example there are two possible overloads, method1(Object) and method1(String). Since String is more specific than Object there's no ambiguity, and the String option will be chosen. If there were a third overload such as method1(Integer) then there is no longer a single most specific choice for the call method1(null), and the compiler would generate an error.
Well in one sentence
In case of Overloaded methods compiler chooses the method with most
specific type, as String is the most specific type of Object compiler
will invoke the method which takes string as an argument
public class Test11
{
public static void method1(String str)//here str is the object of string
{
System.out.println("String");
}
public static void method1(Object obj)//here this is a common object not specified
{
System.out.println("Object");
}
public static void main(String[] arr )
{
Test11 t=new Test11();
String null1=new String();
method1(null1);
method1(t);
}
}
output is :
String
Object
//null1- is a string object if u pass this it will call method1(String str) only because u pass string object
//t-is general object if u pass this it will call method1(Object obj)only because u pass class objct so it will pass object as parameter
on passing object reference to static method m1() why it does not become null and why last statement doesn't give errror. Output is X
class I {
private String name;
public String name() {
return name;
}
public I (String s) {
name = s;
}
}
class J {
public static void m1 (I i){
i = null;
}
public static void main (String[] arg)
{
I i = new I("X");
m1(i);
System.out.print(i.name());
}
}
Java is pass by value so scope of i is limited to m1()
public static void m1 (I i){ // i is copied from i which is in main method but it is another variable whose scope lies within m1() only
i = null; // original i in main lies in main() method scope
}
If you change name of i in method m1(), confusion will be lesser like :
public static void m1 (I iObj){
iObj = null; // i in main() method still points to Object
}
Java uses pass by value exclusively. Changing the value of i within m1 only changes that parameter's value. It doesn't do anything to the variable i within main.
What may confuse you - it certainly confuses plenty of other people - is that although the arguments are passed by value, if the type of the parameter is a class, then that value is a reference... and indeed the value of the i variable in each case is a reference. That reference is still passed by value - the value of the argument is directly copied as the initial value of the parameter. However, if instead of changing the parameter itself you make a change to the object that the parameter value refers to, that's a different matter:
void foo(StringBuilder builder) {
builder.append("Hello");
}
void bar() {
StringBuilder x = new StringBuilder();
foo(x);
System.out.println(x); // Prints Hello
}
See the Java tutorial on passing information to a method or constructor for more details.
Java is pass by value (Read second answer in the link specially)
I i scope of i is limited to method m1 only.
In execution it looks something like:
`I i` in `m1()` points to `null` reference
I i method reference still points to `new I("X");`