This is a pretty simple question but I was wondering about making objects of classes without names. For example, if I had a class 'Zombie' how would I create a new one without assigning a new name each time (e.g., Zombie zombie1 = new Zombie();)
new Zombie() will create a new zombie instance. You do not, however, have to assign it to a local variable or data member if you don't want to. You could, for instance, accumulate these zombies in a collection:
List<Zombie> undeadLegion = new LinkedList<>();
for (int i = 0; i < 1000; ++i) {
undeadLegion.add(new Zombie());
}
What you're referring to is name binding: the association of data with an identifier.
The most common use of binding is to determine the scope of a variable. Bound data is guaranteed by the language to exist (say "in scope"). In Java, the converse is not true: unbound data might still exist on the heap before garbage collection. However, there is no way to access this data, because you have no way to identify it (short of deep magic involving the garbage collector).
You can create unbound data just by writing new Zombie(). You do not have to give it a specific name; it could be an unnamed member of a (named) array:
// Create a new ArrayList<> and bind it to the name list.
List<Zombie> list = new ArrayList<Zombie>();
// Create new Zombie objects, but do not name them.
// Instead, add them to the list.
for (int i = 0; i < 5; ++i) {
list.add(new Zombie());
}
You can also pass an object directly to a function. It won't be bound to any names in the caller's scope, but it will be bound in the callee's scope:
void a()
{
b(new Zombie());
}
void b(Zombie z)
{
}
Here, the new Zombie() is not named in a at all -- but once it's passed to b, it is bound to z.
Finally, you can create an object and do exactly nothing with it:
new Zombie();
It will immediately be unreachable unless its constructor stores a reference to itself somewhere. However, side effects such as printing to the console will still be visible.
Objects don't have names. There is no way to assign a name to the object, nor can you find out what it was at runtime (with help from debug information)
What you may have meant, is how do I avoid declaring a named reference to an object.
The simplest way it to use the reference as an expression like
System.out.println(new Zombie());
Objects don't have names. Variables have names. You don't have to store the result of new into a variable: you can pass it directly as a parameter for example, or just throw it away.
If you want to pass a new object to a method or such, you can just use the constructor call (new Zombie()) without assigning it to a variable.
For example, if you have method called doThingsWithZombie() that takes a Zombie object, you can do the following:
doThingsWithZombie(new Zombie());
You could also add the new object to a list:
LinkedList<Zombie> zombieList = new LinkedList<Zombie>();
zombieList.add(new Zombie()); // Add a zombie
zombieList.add(new Zombie()); // Add a zombie
zombieList.get(0) // Gets the first zombie
Related
I always use constuctor only for attributes of one object.
But i thin when i wrote this :
public Predmet(int esp,int obaveze,int cena){
this.cena=cena;
this.obaveze=obaveze;
this.esp=esp;
List j = new ArrayList();
j.add(8);
this.nesto=(int) j.get(0);
}
where are stored this ArrayList,does it part of object,or is on stack and have reference to array in heap?
The ArrayList is created on the heap and only referenced by the local variable j from the stack here. After the execution of the constructor it will be eligible for garbage collection.
Constructor is working very similar the way methods work. At runtime, anything you define inside constructor/method are called local variables. Their scope will end as soon as execution hits the end of the constructor/method. After consturctor, your list will be eligible for GC. However, this.nesto will still get value 8 as its primitive type.
First, please don't use single variable names! This is bad practice and makes files harder to read. Using a more descriptive name helps to promote code readability.
The way that List j is created, it only exists in the scope of the constructor. After your constructor, List j is no longer accessible. If you wanted it to be accessible after the constructor, have a field for the object. For example:
public class Example {
private int specialNumber;
private List<Integer> numberList;
/**
* Constructs a new Example Object
*/
public Example(int exampleNum){
// specialNumber can be accessed from a Getter method (getSpecialNumber)
this.specialNumber = exampleNum;
this.numberList = new ArrayList<Integer>();
this.numberList.add(exampleNum);
// numberList is a field of this Example now
List<Integer> disappearingList = new ArrayList<Integer>();
disappearingList.add(exampleNum);
// After this method finishes, disappearingList will be gone
}
// disappearingList is no longer accessible
/**
* Gets this Example's specialNumber value
* #return int this.specialNumber
*/
public int getSpecialNumber(){
return this.specialNumber;
}
/**
* Gets this Example's numberList
* #return List<Integer> this.numberList
*/
public List<Integer> getNumberList(){
return this.numberList;
}
}
There is probably a way to hook into some of the Java cleaning methods and pull it out, but that will get a little messy. If you want to be able to create an Object inside another Object, and use it after the constructor, it must be saved as a field.
I understand that immutable means that it is an object that will not change state after it is instantiated. But in this line of code I dont see Final when the array values is declared.
Is this class immutable? Can anyone explain how to find out. Thanks
public class A {
private double[] values;
public double[] getValues(){
return values;
}
}
As other have written this object is considered to be mutable in its state. What it is immutable to is that you can not exchange the array it holds. But you can change the array's content (getValues()[0] = 10;).
To convert this to a immutable object you must use List instead of an array. With List you can use Collections' method unmodifiableList to convert a given list into a version you can savely expose to the outside. If the caller of getValues() uses add or remove on a unmodifiable list it will result into a UnsupportedOpertionException keeping your object save from being modified.
If you need to stick to arrays you need to provide a copy (System.arraycopy) or a clone (clone()) of the array.
Usually a object is considered to be immutable if you can not change its properties (including inherited properties from superclasses. This usually includes the properties values as well but this is a blurred definition.
For example if you have a class that holds a File instance which points to document file and this File instance can not be changed the class is considered to be immutable (the inforamtion it provides never changes) but the document it points to can be mutated and changed every time. So its a blurred line actually (remember in your example you can not change the array but the content of the array).
Yes the code pasted is not having any final keyword associated and has no immutable behavior.
Well i would like to bring forth some key guidelines related to writing immutable classes in java :
1.) Ensure the class cannot be overridden - make the class final, or use static factories and keep constructors private
2.) Make fields private and final
force callers to construct an object completely in a single step, instead of using a no-argument constructor combined with subsequent calls to setXXX methods (that is, avoid the Java Beans convention)
3.) Do not provide any methods which can change the state of the object in any way - not just setXXX methods, but any method which can change state
4.) If the class has any mutable object fields, then they must be defensively copied when they pass between the class and its caller
A a = new A();
a.getValues()[0] = 1.2;
This would work as long as values is not empty. You will however not be able to reassign values to a new array. That is: a.getValues() = new double[5]; will not work.
The class is not immutable, as I can change values, just not reassign it.
Here is a simple verification. the values are initialized to 1,2.
Using the getter and a reference, one is able to change the values inside the first item in the array after the object is created
public class A {
private double[] values;
public double[] getValues() {
return values;
}
public static void main(String[] args) {
A test = new A();
test.values= new double[]{1, 2};
double[] valuesref = test.getValues();
valuesref[0] = 10;
for (int i = 0; i < test.values.length; i++) {
System.out.println(test.values[i]);
}
}
}
This can be avoided if getValues() returns a copy of the array.
#edit IT works, thanks for the answers:) I guess my bad was when I thought that
WORLD[i]=global.Values.CHUNKPATTERN();
simply takes the object on the right, clones its value('s), and assigns them to part on the left, while it turns out that it establishes a reference between two. Thanks again:)
I have simple begginer/newbie array problem:
for(int i=0; i<global.Values.WORLDVOLUME(); i++)
// global.Values.WORLDVOLUME() --> const, int. always the same.
{
WORLD[i]=global.Values.CHUNKPATTERN(); //to pre-define as 'zero only' object. Always the same. Const.
WORLD[i].chunknr=i+1;
}
System.out.println(WORLD[4].chunknr);
Of course I want WORLD[0] to have chunknr 1, WORLD[4] to have chunknr of 5 and so on.
Instead WORLD[i].chunknr=i+1; seems to update chunknr of ALL elements(not only WORLD[i]).
So that it looks like WORLD[0].chunknr = WORLD[1].chunknr=global.Values.WORLDVOLUME() here.
Anyone knows how to bypass that? I belive there's a simply solution...
Do I understand the array of objects correctly?
You can Have like(providing you have the class and constructor)
Point POINTARRAY[]= new Point[10];
POINTARRAY[1].x=5
POINTARRAY[1].y=6
POINTARRAY[3].x=17
POINTARRAY[3].y=1
Right?
How to assign that via loop?
Instead WORLD[i].chunknr=i+1; seems to update chunknr of ALL elements.
Are WORLD[0] and WORLD[1] different objects? They are not different if `WORLD[0] == WORLD[1] evaluates to true.
You have:
WORLD[i]=global.Values.CHUNKPATTERN();
Does CHUNKPATTERN create a new object every time it is called?
I bet this method
WORLD[i]=global.Values.CHUNKPATTERN();
always returns the same instance of an object so you have a reference to the same object in every slot of your array.
Subsequently
WORLD[i].chunknr=i+1;
you change the attribute chunknr of the same object in every iteration. You say
...seems to update chunknr of ALL elements
kind of true, because all elements reference the same instance.
You need to find a way to have global.Values.CHUNKPATTERN(); return a new object every time.
This line is your problem:
WORLD[i]=global.Values.CHUNKPATTERN();
This is assigning WORLD[i] a reference to global.Values.CHUNKPATTERN(), meaning that they both point to the same object! And for each iteration of your loop you are just creating more and more references to the same global object.
Sometimes this isn't what you want. In this case you need to copy the value, which can be done in a number of ways, but in most cases you can simple clone it. All Java objects support a clone() method, although sometimes you need to override it to do the correct thing for your class.
All this means is that you should replace the above line with:
WORLD[i]=(YourType)global.Values.CHUNKPATTERN().clone();
where YourType is the actual type of the class, since you omitted that from the code snippet you posted.
Hope that helps!
I guess the following line returns always the same reference:
global.Values.CHUNKPATTERN();
so the different array indices are actually point to the same referece. It's only a guess because you didn't tell us how the above function works.
Here's an example of what different array element could point to the same instace:
public class AClass{
public int val = 0;
}
AClass[] array = new AClass[2];
AClass classInstance = new AClass();
array[0] = classInstance;
array[1] = classInstance;
The code above instatiated a single AClass object (classInstance), but use 2 different array elements to reference the same instance:
System.out.println("array 1 value " + array[1].val ); // both element initialized to 0 so it prints 0
array[0].val = 15; // actually is classInstance.val to be modified, through the reference to it stored inside the first element of the array.
System.out.println("array 1 value " + array[1].val ); // print 15
For what concern the POINT example, you can use for loop this way:
Point POINTARRAY[]= new Point[10];
for(int i = 0 ; i < POINTARRAY.length; ++i)
{
POINTARRAY[1].x=...;
POINTARRAY[1].y=...;
}
class A
{
static int i;
A()
{
System.out.println(++i);
}
public static void main(String h[])
{
A obj[] = new A[30];
}
}
A obj[30] = new A[30]; :- this line should invoke the default
constructor 30 times ?
The line
A obj[30] = new A[30];
does not call the constructor for A. It creates 30 uninstantiated references to A;
To instantiate the 30 object references, you can use:
A obj[] = { new A(), new A(), ..28 more ->
};
or better in this case given the number of elements:
for (int i=0; i < obj.length; i++) {
obj[i] = new A();
}
Note, the first use of 30 in the array size declaration is illegal.
A obj[30] = new A[30];
^
No, this line does not invoke constructor at all. It just creates 30 elements long array of type A. Each element of array is null.
There is no way to do exactly what you want to do, but here are two things that come very close, both calling the default constructor 30 times:
A *obj = new A[30];
or
A obj[30];
The first answer will create an array of 30 A objects on the heap, calling the default constructor for each one of them. obj can be passed back to callers of this function since it is not on the stack. The problem is, obj no longer has a type of A[30], so sizeof(obj) will be different from the code in the original question. (Note that "delete []" must be used for obj, not just "delete".)
The second answer will create an array of 30 A objects on the stack. Now the compiler will understand the obj has 30 elements, and sizeof(obj) will be the same as in your question. However, obj can only be used within this function (or functions that it calls) because once the function returns, it will be eliminated from the stack, calling 30 destructors in the process. (It is a local variable only.)
With C++ (or any good object oriented language), creating an object always means both allocating the space and calling the constructor. Otherwise, you really don't have a useful object. So, when an object is created in any supported way (local variable or "new" for C++), it always calls the default constructor for every object you created and now have access to. (Note that if there were no default constructor, then neither answers would even compile!)
Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}