I have a static function that takes a parameter called X.
In this static function I create an anonymous class. This class should have a member variable, also called X.
From the functions in the anonymous class, how can I access the function's parameter X?
To illustrate:
class Test {
static void func(final List<T> X) {
new Test() {
final T[] X = ?.X.toArray();
};
}
}
In my real code I want to create an array in my anonymous class from a list argument (via toArray() in the anonymous class's initialisation), and I want to re-use the same variable name rather than using hungarian notation to differentiate them.
This isn't possible in Java. Function parameters have no "namespace" like this which you could use to denote which variable you mean.
The only solution is to create an arbitrary prefix like outerX for the outer parameter or xAsArray for the inner.
Related
I have a function multi2 which returns inner class Inner as an Object.
What happens to a - where is it saved and how can I access it?
public class C {
private static Object multi2(final int a) {
class Inner {
public int hashCode() {
return 2*a;
}
}
return new Inner(); // What happens to a?
// Who allocates a?
// Can I Access a?
}
public static void main(String[] args) {
Object o = multi2(6);
System.out.println("o.hashCode() = " + o.hashCode());
o = multi2(4);
System.out.println("o.hashCode() = " + o.hashCode());
}
}
What happens at the implementation level is that a copy of the value of a is saved in a synthetic instance variable declared in the compiled version of the C.Inner class.
The value of a is passed to the compiled Inner constructor via an extra parameter.
The C.Inner.hashCode method uses the value of the synthetic variable. Accessing a in the source code of Inner.hashCode is transformed into accessing the corresponding synthetic variable in the compiled code.
The variable in the outer scope must be final1. The synthetic variable must be final2 in the Inner class. This maintains the illusion that (potentially) multiple instances of the Inner class are seeing the same a variable. (They aren't, but since the variable(s) can't be changed, it is not possible for the code of the inner class to tell the difference.)
If you use javap to look at the bytecodes for the compiled example, you will see the mechanisms used to implement this in the outer and the inner classes.
1 - or effectively final from Java 8 onwards.
2 - If a could be mutated by an Inner method, then two Inner instances with the same outer class need to share a mutable variable whose lifetime is (now) longer than the stackframe for a multi2 call. That entails somehow turning a from stack variable into something that lives on the heap. It would be expensive and complicated.
You have defined the class Inner inside the function so the scope of the class will be
restricted with in the method. And your function is static so it will be live as long as the class definition is loaded. You have override the hashCode function inside the InnerClass so every time you are calling the multi2(param) you are creating the hashCode for the instance of InnerClass and returning the instance of the InnerClass.
So as for you questions, please correct me if i am wrong.
What happens to a ?
a is with in the scope of your static method, so it will be live as long as the class definition is loaded.
Who allocates a?
scope of a is restricted inside the static method and static method does not require instance to access it but as for the static method/variable allocation, i think it depends on JVM.
Can I Access a?
No you cannot access a from outside you static method, it is restricted with in your static method.
Since the "a" is a local parameter, you could use a different approach to read the "a" value:
public class C {
public static Object multi2(final int a) {
return new Inner(a);
}
public static void main(String[] args) {
Object o = multi2(6);
System.out.println("o.hashCode() = " + o.hashCode());
System.out.println("o.getA() = " + ((Inner) o).getA());
o = multi2(4);
System.out.println("o.hashCode() = " + o.hashCode());
System.out.println("o.getA() = " + ((Inner) o).getA());
}
}
class Inner{
public int valueA;
public Inner(int a)
{
valueA = a;
}
public int getA() {
return valueA;
}
public int hashCode() {
return 2*valueA;
}
}
I wanted to know what was actually happening, so I compiled your code and looked at the bytecode output.
Basically what happens is the compiler adds in a constructor to your class 'Inner'. It also adds a single parameter to that constructor which takes 'a'. If your multi2() method was NOT static then there would probably also be a parameter to take 'this' where 'this' is the instance of 'C' that multi2() is executing on. BUT since we're in static context, there is no 'this'.
The compiler adds a private final field to your class 'Inner' and sets that private field using the value passed via the constructor. The compiler also converts
new Inner()
into
new Inner(a)
Hashcode then accesses the private field containing the value for a.
If 'a' was an object instead of a primitive, then it would be the same way, but a reference would be passed through instead of an actual number value.
How do you access this variable? Well you access it with reflections, but there are many problems:
1) You don't know the name of the field made by the compiler, so you can only get the name by looking at the bytecode. Don't trust decompilers as they might change the name. You gotta look at the bytecode yourself to find out.
2) The compiler probably marks the field as final, which means even if you can get reflections to access the field for you, you won't be able to update it.
3) It is entirely up to the compiler to figure out field names. Field names could change between builds depending on the compiler and it's mood.
Inner is a so called local class. a is a parameter passed to the method multi2 and accessable within that scope. Outside of that method, you cannot access a.
A ton of questions have been asked on how to create getter and setter methods in java. But i have yet to see one that actually tells me how to use it.
Say i have Private int i = 1; in class A and i want to access it in class B.
I would first create a get method in class A called getIntI(); which would return the value of i.
Then in class B if i wanted to create an if statement that would need the value of i how would I get int i's value. The following is my try and calling the get method which does not work.
if(getIntI == 1)
{System.out.print.ln("int i is one");}
It is probably a really stupid question but i cant find an answer for it elsewhere.
In class A:
public int getIntI(){
return i;
}
Note: Now since your variable is single character named (just I), getter method is named getIntI since the name getI makes lesser sense. But generally, getter methods are something like get+VariableName and do not involve mentioning type. For example if I had a variable called int count, my method would be named getCount instead of getIntCount. Thats the general convention.
Also, naming variables in single char formats (like x, y etc) is discouraged because it may create confusion and management difficulty in complex programs. Though in very small programs they are fine.
Moving back to topic, if you want to access method getIntI() in class B, you will either have to inherit class A or create an object of class A reference to its method.
For class B:
Creating object
A obj = new A();
if(obj.getIntI() == 1)
// Do stuff
Inheriting class A:
public class B extends A{
... // Your stuff
if(getIntI() == 1)
// Do stuff
... // Your stuff
}
Of course there are other ways but these are simpler ones.
if class B extends class A then do only this changes,
if(getIntI() == 1)
If above inheritance was not there then do this,
if(new A().getIntI() == 1)
The problem is that you need to create a object derived from class A before you can access its variables/methods using
A a = new A();
where "a" is the name of the object. Then you can access the getter method by calling a.getIntI. You can also declare the int variable as static so that you wouldn't have to instantiate any objects. An example of class A with the static variable and getter method would be:
public class A {
private static int i = 1;
public static int getIntI() {
return i;
}
}
With this, you can call the getter method with A.getIntI().
First, if you want to access one of A's non-static methods (in this case, getIntI), you need an instance of A, or you can just declare it static.
Secondly, A method call needs a parameter list, even an empty one is needed. getIntI does not need any parameters, so you should add () at the end.
Now, you can get an instance of A somewhere and call it aObj. Andd then you can use it in the if statement:
if (aObj.getIntI == 1)
And remember to add ()!
if (aObj.getIntI() == 1)
Alternatively, you can declare i in A as static. There are two main differences between a static and a non-static variable.
You don't need an instance of the declaring class to access the static variable.
Unlike non-static variables, there is only one static variable. If you have a non-static variable i, you can create lots of instances of A and each instance will have its own i
Now let's see this in action, declare i as static:
public class A {
private static int i = 1;
public static int getIntI () { return i; }
}
Note how both i and getIntI are declared static.
Then you can use in a if statement like this:
if (A.getIntI() == 1)
Note how I use the class name A to access the method, not an instance of A.
I'm having difficulty understanding the concept of the new keyword. I know its used to instantiate objects; e.g. If I had a class called Superclass, I could create a object of that class by writing:
Superclass supeclassobject = new Superclass();
I understand that but what I dont understand is that this is also acceptable:
E.g. if your were passing a Superclass object to a method which takes it as an argument, then the following would still work:
public void MethodTakingSuperClassObjectAsArugment (new Superclass()){
*CODE HERE*
}
I cant understand how that works. You haven't given a name to the object so how could you refer to it in the method? This makes sense to me:
Superclass sobject = new Superclass();
public void MethodTakingSuperClassObjectAsArugment (sobject){
*CODE HERE*
}
You have a few misconceptions there.
First, there is a method definition, and then there is a method invocation.
Method definition is where you declare your method. You give it modifiers such as public/private/protected, a return type, a name, a list of parameters, an optional throws and a body:
public static int myInt( double myParameter ) {
return (int)myParameter;
}
Here, the parameters must have names. Otherwise, you would not be able to refer to them in the body.
And then there is the method invocation. Within some other method, like main, you call your method:
int a = myInt( 15.7 );
You passed 15.7 without giving it a name. The value that you actually pass in a method invocation is called an argument as opposed to a parameter, which is the formal name and type given in the method definition.
If your method definition included a parameter of the type SuperClass, it would look something like:
public static void myMethod( SuperClass myParameter ) {
...
}
You can't use new in a parameter declaration. But when you invoke the method, and you have to pass an argument to it, you can use:
myMethod( new SuperClass() );
In the same way that you didn't need to give a name to your 15.7 before, you don't need to give a name to your new object now. When Java passes it to the method, the method sees it as the value of myParameter.
Your second misconception is about names of objects. Objects don't actually have names. But they do have references. You can refer to an object from a local variable, from a field or from inside another object. In those cases, you give the reference a name, not the object. So you can do something like this:
Superclass myVar = new SuperClass();
Superclass anotherVar = myVar;
What you have here is two reference variables. You assign a reference to a new object to myVar. And then you assign a reference to the same object to anotherVar. Both myVar and anotherVar refer to the same object. The object does not have a name. You can now do something like myVar = null. But the object will still exist, and you'll be able to access it through anotherVar.
Think of reference variables as arrows. You give the arrow a name, and you can point the arrow at any object of the appropriate type. Or you can assign null to it which means the arrow is not pointing at anything.
Back to the issue of parameters, sometimes you can see something like this:
myMethod( new SuperClass() {
// Code here
} );
This is exactly the same as we did before. It's a method invocation. The code you see in the braces is not the code for myMethod. It is in fact the code for the new object. It's an anonymous class, which extends SuperClass, and has some of its own code in those braces. So the class is defined and an instance is created of it, and that instance - of an anonymous class extending SuperClass is what's being passed as an argument to myMethod. Inside myMethod, it can be accessed with myParameter. It's the same as writing this somewhere in the same file:
private class SomeClass extends SuperClass() {
// Code here
}
And then calling `myMethod` like this:
myMethod( new SomeClass() );
I wrote this in my main because I want to call this method bla_methods from my main.
I wrote an method called bla_methods already. The main isn't letting me call my bla_method.
Sorry, I should have clarified myself. But, thanks everyone!
bla_methods (one_data[], two_datas[], length);
then I get this error for one_data[] and two_datas[]
<<gradeabc.java:45: error: '.class' expected >>
You declare methods within your class, but outside of other methods (unless it's a method in an inner class)...
public static void bla_methods (String[] one_data, int[] two_datas, int length) {
// do something.
}
public static void main(String[] args) {
// ...
}
Should work.
No, Java doesn't allow you to define methods inside of other methods - main included.
Just put the method inside the same class as main.
You didn't specified the data type of the array, that's why you got the error.
private static void bla_methods (DATA_TYPE[] one_data, DATA_TYPE[] two_data, int length){
//your code
}
public static void main(String[] args){
bla_methods(a, b, c);
//
}
the "DATA_TYPE" int bla_method can be any data type. such as int, float etc. it can also be an Object of a class, such String...
Methods cannot be nested.
You can only create a method directly inside a class.
You have to understand a few things to be able to work in Java:
Everything, methods and members are parts of either a class or an object. By inside I mean they are inside their block, marked by {}.
A class is declared by the class keyword followed by the name of the class. Example: class foo {/*...*/}
An object is an instance of a class, which is usually instantiated by the new keyword. Example Foo bar = new Foo();
Members can be members of an object or a class (if they are static). They have a type and they might have an initial value. Example: Foo bar = new Foo();
Methods can be methods of an object or a class (if they are static). Methods have a return type, a parameter list and a block of their own, where the exact receipt/algorithm of the method is defined. Example: static public void main(String args[]){/*...*/}
Members represent the state of the object/class where they are applicable.
Methods represent the ability of the object/class where they are applicable.
A parameter is inside the brackets of a method, they have a type as well. Example: public static void main(String args[]){/*...*/}
A variable behaves almost like a member, but it is defined inside a method and is applicable only there.
I think you should read a tutorial, for example this one.
So, you did not associate a type to your variables/parameters and I doubt that your method was defined correctly.
Can variables be abstract in Java? Do constructor support abstract variables? I am not sure but I think the constructor supports static variables. Please clarify my doubt.
In java only classes and methods can be abstract. Variable declarations cannot. However you can have variable declarations whose types are abstract. See example:
public abstract class MyClass { // allowed
public abstract myMethod(); // allowed
public MyClass instance; // allowed
public abstract MyClass instance; // NOT ALLOWED!!
}
The language specifacation lists 7 types of variables:
class variables - declared as static within a class declaration
instance variables - declared within a class declaration without using the static keyword
array components - like i[2] when we create an array like int[] i= new int[5]
method parameters - name argument values passed to a method
constructor parameters - name argument values passed to a constructor
exception-handler parameter - created each time an exception is caught
local variables - declared in a block ({ }) or for statement
You can use all variable types (except #4) in a constructor:
class Demo {
static int demo1 = 0; // class variable
int[] demo2 = new int[5]; // instance variable
Demo(int demo3) { // constructor parameter
try {
int demo4 = // local variable
demo2[2]; // array component
} catch(RuntimeException demo5) { // exception-handler parameter
}
demo2 = new int[]{Demo.demo1}; // using class and instance variable
// in a constructor
}
int method(int demo6) { // method parameter
}
}
The abstract keyword is not allowed for variable declaration.
abstract is a non-access modifier in java applicable for classes, methods but not variables. It is used to achieve abstraction which is one of the pillar of Object Oriented Programming.