Java noob question:
Consider the following C array and initializer code:
struct {
int x;
int y;
} point_t;
point_t points[1000];
Easy. This gets created and memory allocated at load time.
Now consider the similar in Java:
public class point_t
{
public int x;
public int y;
}
point_t points[] = new point_t[1000];
// Without this loop, java will crash when you run this
for (int i=0; i<1000; i++)
{
points[i] = new point_t;
}
points[0].x = 10; // Crash would occur here without above loop
points[1].x = 10;
Initially my java program was crashing with a null pointer dereference. The problem was that, coming from C++, I was not aware that you have to create the 1000 point_t objects. Just a comment but this seems INSANE. Suppose the array size was 1 million or 1 billion. It would literally take seconds simply to "create" this array with empty entries at run time. In C++ it all happens at load time. I admit that you don't always know what would be in the C++ array's cells, but in embedded systems where I work, quite often the memory is auto initialized to zeros so it works.
So is there any easier, quicker, more efficient way in Java to create an array and allocate the memory when you have an array of objects? Or am I doing something wrong in the code above?
Since you are coming from a C++ background, this may help. In Java, when you write
point_t points[] = new point_t[1000];
This is similar to writing, in C++,
point_t* points[] = new point_t*[1000];
That is, in Java, when you create the array, you are not creating an array of point objects, but rather and array of point references, the same as if you would have created an array of point pointers in C++.
Java is a managed (garbage-collected) language; that is what Java programmers would expect.
As for the second part of your question, how one would create the objects themselves, what you did is fine. Create 1000 point objects in a loop and load them up. If you want shorter code, you can write a nice method to do this work. :)
You can also look into other collection libraries that might have these kind of convenience factory methods.
Writing
point_t[] points = new point_t[ 1000 ];
is allocating a thousand references to point_t objects. (In C parlance, it's allocating pointers to structs of that type.)
That loop
for (int i=0; i<1000; i++)
{
points[i] = new point_t;
}
allocates a new point_t object, and puts the references (pointer) to it in the array. Until you did that, the array was nothing but nulls, and it probably gave you null exceptions.
That's not an array of point_t instances; those live out on the heap.
It's really an array of references to those point_t instances out on the heap.
Any reference that is not initialized by being assigned to a reference value (e.g. by calling new) is set to null.
It's true for non-array reference types, too.
public class Person {
private String name; // not initialized; that means it's null
public Person() {} // oops; constructor should have initialized name, but now it's null
public String getName() { return name; } // returns null unless you set it properly
public void setName(String newName) { this.name = newName; }
}
You can use the Flyweight pattern to share the same data between different objects and defer the creation of the point object until it is really necessary
Related
I am facing a confusion while working with objects. I searched google but couldn't find actual words to search for. The question is:
I am working with objects which consist some other object. For example:
public void mapObjects(A a, B b) {
a.setWeight(BigDecimal.valueOf(b.getWeight));
//Now my doubt lies here
if (a.getCharges.getDiscounts.getDiscountList != null) {
for(int i = 0; i < a.getCharges.getDiscounts.getDiscountList.size(); i++){
b.getList().get(0).setDiscountValue(a.getCharges.getDiscounts.getDiscountList.get(i).getValue());
b.getList().get(0).setDiscountName(a.getCharges.getDiscounts.getDiscountList.get(i).getValue);
}
}
}
The above code is just an example. The project in which I am working uses similar type of coding style. The usage of a.getCharges.getDiscounts.getDiscountList() kind of code always bugs me. Because I am again and again calling the same statement.
When I asked a senior why dont we save this statement into a simple List<> variable. He told me that it will use extra references which will increase overhead. Can using a variable be that much overhead than calling getters again and again?
As Java exchanges references not actual object, if you take a local variable it will just add a reference variable entry in stack frame.
This memory would be very less, almost negligible
This memory will be released once the method is completed because this will be local to the method
Despite that, you can gain significant performance gains if you use local variables. You are extracting same information within loop multiple times.
a.getCharges.getDiscounts.getDiscountList.size() is called multiple times. It should be a local variable.
b.getList().get(0) is being called multiple times. It should be a local variable.
a.getCharges.getDiscounts.getDiscountList is called multiple times. It should be a local variable.
Changing these to local variables would results in good performance gains, because unnecessary method calls would be saved.
Point your senior to this. If it works for limited resources on Android, I guess the technique of storing in local variables everything used in a for cycle is actually beneficial for performance anywhere.
In the excerpt below, note that we aren't even speaking about the overhead introduced by calling the (virtual) list.size() method, only storing the array.length as a local variable produces notable differences in performance.
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
zero() is slowest, because the JIT can't yet optimize away the cost of getting the array length once for every iteration through the loop.
one() is faster. It pulls everything out into local variables, avoiding the lookups. Only the array length offers a performance benefit.
two() is fastest for devices without a JIT, and indistinguishable from one() for devices with a JIT. It uses the enhanced for loop syntax introduced in version 1.5 of the Java programming language.
Just make the discountList field never null - ie initialized to an empty list - and iterate over it. Something like:
for (Discount discount : a.getCharges().getDiscounts().getDiscountList()) {
b.getList().get(0).setDiscountValue(discount.getValue());
b.getList().get(0).setDiscountName(discount.getName());
}
Your "senior" may need to do some research. The "performance impact" of doing this is a few bytes per object and a few microseconds per access. If he's really hung up about memory, initialise it with a LinkedList, which has almost no memory footprint.
In Java a variable V pointing to an object instance O is simply a numeric value pointing to a memory location where the object's data is stored.
When we assign Vto another variable V1 all that happens is that V1 now points to the same memory location where data for O is stored. This means that new memory is not allocated when you do simple assignment unlike C++ code where the = operator can be be overloaded to do a deep-copy in which case new memory is actually allocated. Illustrating with an example below
Consider a class like below
class Foo {
private List<String> barList = new ArrayList<>();
//class methods...
//getter for the list
List<String> getBarList() {
return this.barList;
}
}
public static void main(String[] args) {
Foo f = new Foo()
//the below lien will print 0 since there is no bar string added
System.out.println("Bar list size: " + f.getBarList().size());
// add a bar string. Observe here that I am simply getting the list
// and adding - similar to how your code is currently structured
f.getBarList().add("SomeString");
//now get a reference to the list and store it in a variable.
// Below anotherList only points to the same memory location
// where the original bar list is present. No new memory is allocated.
List<String> anotherList = f.getBarList();
//print the content of bar list and another list. Both will be same
for(String s : f.getBarList()) {
System.out.println(s);
}
for(String s: anotherList) {
System.out.println(s);
}
//add a new bar string using the reference variable
anotherList.add("Another string");
//print the content of bar list and another list. Both will be same. If anotherList had separate memory allocated to it then the new string added would be only seen when we print the content of anotherList and not when we print the content of f.getBarList(). This proves that references are only some numeric addresses that point to locations of the object on heap.
for(String s : f.getBarList()) {
System.out.println(s);
}
for(String s: anotherList) {
System.out.println(s);
}
}
Hope this helps.
This question already has answers here:
C++ Pointers to Pointers in Java
(5 answers)
Closed 7 years ago.
For last some day I am learning Java while I have some knowledge in C. Now I am trying to convert code written in C to a Java code. There I found a pointer to pointer (pptr)variable declaration like this -
int n;
int *ptr;
int **pptr;
n = 13;
ptr = &n;
pptr = &ptr;
As far as I know, in Java there is no pointer type variable. My question is there any way to represent pptr or anything equivalent of pptr in Java?
Let's look at some of the use cases for multiple indirection in C, and see how they apply to Java.
Use Case #1: you want a function or method to change the value of a pointer or reference parameter such that it points to a new object, and have that change reflected in the caller.
In C, that would look something like this:
void foo( T **p )
{
*p = new_value(); // update the thing p points to
}
void bar( void )
{
T *var; // for any type T
foo( &var ); // foo will set var to point somewhere else
}
var is a pointer to something, and we want the function foo to change var such that it points to something else. Since C passes all function arguments by value, if we want foo to update var, we must pass a pointer to var, giving us a pointer to pointer type in foo.
Java doesn't expose operations on pointer types (no unary & address-of or * indirection operators), so we can't do this directly. We'd have to wrap the reference we want to change in another reference type and pass that wrapper type to the method, and even then I'm not sure it would do the same thing as the C code above:
public class thing
{
// attributes
}
public class thingWrapper {
{
public thing t;
}
public void pointToNewThing( thingWrapper tw )
{
tw.t = newThing();
}
public void bar()
{
thing t = new thing();
...
thingWrapper tw = new thingWrapper();
tw.t = t;
pointToNewThing( tw );
t = tw.t;
...
}
Use Case #2: you want to allocate a multi-dimensional array in a piecemeal fashion, rather than in a single operation. This is useful if you want a "jagged" array (where the number of elements in each row isn't uniform) or if you're trying to allocate a lot of memory and don't have a single available block large enough for the whole thing.
In C, you'd do something like
T **arr = malloc( N * sizeof *arr );
if ( arr )
{
for ( int i = 0; i < N; i++ )
{
arr[i] = malloc( M * sizeof *arr[i] );
}
}
because C arrays are not "first class" objects, and cannot be manipulated and assigned directly, so you have to do this through pointers.
Java treats arrays completely differently such that you don't need to do the pointer-to-pointer dance at all:
T arr[][] = new arr[N];
for ( i = 0; i < N; i++ )
{
arr[i] = new arr[M];
}
I can't think of other use cases off the top of my head, but that should give you a flavor of how you'd translate the C concept to Java.
The short answer is yes. But first, a lesson in Java...
In Java, whenever you use objects, pointers are involved. If you have an object, the variable that "holds" that object is actually a pointer to that object. So if you are working with objects, you are already using pointers.
Now for primitive data types (e.g., integers, chars, or floating point numbers), Java does not use pointers, though. So if you want pointers for primitive data types, you need to use a wrapper class, such as Integer, which effectively promotes the value to an object.
Note, however, that the default wrapper classes are immutable.
If you want double-pointers (a pointer to a pointer) or triple pointers, you will need to create custom wrapper classes, like an ObjectWrapper class, that allows you to set up an arbitrary number of objects each pointing to (or "holding") the next.
What you can do is create an int array even with a size of 1 this way when you access the array it will always refer to the same place in memory as far as your programming is concerned.
C++:
Student* sp = new Student[10];
Now, please correct me if wrong. I believe this creates an array of 10 instances of Student, each calling the default constructor with no arguments.Please use arrays and not vectors.
Java:
Student [] sa = new Student[10];
Again, correct me if I'm wrong but I think in case of Java though, no instances are created when this statement executes and instead only memory is reserved to hold 10 references to Student instances.
And it is necessary that we follow it up with:
sa[0] = new Student(*arguments*);
sa[1] = new Student(*arguments*);
.
.
.
sa[9] = new Student(*arguments*);
I'm trying to see the difference and quite frankly, I'm confused. Kindly clarify please.
What do you mean, you're trying to see the difference and you're confused? The difference is exactly what you've stated. The C++ code creates an array of 10 Student objects that are default-initialized [1], and the Java code creates an array of 10 references so no Student constructors are called until you do it yourself.
Maybe your question is why C++ and Java differ. That's because a Student[] in Java is an array of Student references, so the true C++ equivalent would be an array of Student pointers,
Student** sp = new Student*[10]
which you would indeed have to follow up with
sp[0] = new Student(args);
...
sp[9] = new Student(args);
analogously to your Java example.
Now, if you want an array of 10 Student objects in C++ initialized using a constructor other than a default constructor, you have to do it in two steps: first allocate memory for 10 Student objects, then manually construct the Student objects over that memory using placement new. I do not endorse this style of coding. It is very confusing even to experienced C++ programmers.
typedef Student SA[10]; // SA means array of 10 Students
SA* psa = static_cast<SA*>(::operator new(sizeof(SA)));
SA& sa = *psa; // sa refers to an array of 10 Students
new (&sa[0]) Student(args); // construct the Student object
// ...
new (&sa[9]) Student(args);
// later
for (int i = 0; i < 10; i++) {
sa[i].~Student(); // destroy the Student object
}
::operator delete(psa); // deallocate the memory for the array
Use a damn vector.
[1] Note: In C++, for a class, default-initialized means that the default constructor is called; for an array, it means each element is default-initialized; and for an arithmetic, pointer, reference, or enum type, it means it's not initialized at all.
Short answer:
Those two declarations are different. The C++ one allocates an array of Student objects, while the Java one allocates an array of references to Student objects.
Long answer:
The difference is that, in Java when you declare an object:
Student s;
It creates a reference (similar to a pointer in C++) to a Student and initializes the reference to null. You can then later assign a Student object to that reference variable with s = new Student().
But in C++ when you declare an object:
Student s;
It creates an actual object (not a reference to an object as in Java). And thus the object must be immediately instantiated.
So in Java, when you do this:
Student [] sa = new Student[10];
It actually creates an array of references to Student objects (not an array of actual Student objects), and they are all initalized to null references.
...I think in case of Java though, no instances are created when this statement executes and instead only memory is reserved to hold 10 references to Student instances.
So yes, you're right.
But in C++ this:
Student* sp = new Student[10];
dynamically allocates an array of actual Student objects. Again, not references as in Java, so each object will be instantiated immediately.
I believe this creates an array of 10 instances of Student, each calling the default constructor with no arguments.
Correct as well.
So in Java after declaring the array of references you can then instantiate the actual objects and assign them to those references in the array with this:
sa[0] = new Student(*arguments*);
But in C++ the Student objects in the array were already instantiated, so this is not needed.
Bonus: Array of pointers in C++
In C++, you can also declare an array of pointers to postpone object instantiation, similar to the Java array of references:
Student** spp = new Student*[10];
This will create an array of 10 pointers to Student objects. You can then instantiate the objects when needed and assign their memory addresses to the pointers:
spp[0] = new Student(*arguments*);
This looks a lot like Java, but is actually not generally recommended in C++. In fact, using new in C++ should be avoided most of the time.
Here's a round about way of accomplishing what you are hoping to using the new operator.
#include <new>
struct Student
{
Student(int ){}
};
int main()
{
// Allocate memory for 10 Students.
// Don't construct Student objects yet.
char* cp = new char[10*sizeof(Student)];
// Now construct the Student objects using
// placement new
Student* sp[10];
for ( int i = 0; i < 10; ++i )
{
sp[i] = new (cp + sizeof(Student)*i) Student(10);
}
// Use the Student objects
// ...
// ...
// Call the destructor on the Students explicitly.
for ( int i = 0; i < 10; ++i )
{
sp[i]->~Student();
}
// Deallocate the memory.
delete [] cp;
}
So here it goes. I've been building a piece of software for a bigger project, and right now, I am simply baffled by the way Java treats my code. I have absolutely no idea as to why Java behaves the way it does right here.
It seems to skip part of my code, and assigns values to a different array than I expected when no according method is called.
I have walked over this for a few hours now with the IntelliJ Debugger, inspecting everything ever so closely, but I have not found a single reason as to why things happen the way they do.
package com.whatareyoudoing.java;
import java.util.Arrays;
/**
* WHAT THE ACTUAL DUCK
*/
public class WTF {
private int[] number;
private int[] oldNumber;
public WTF() {
number = new int[1];
oldNumber = new int[1];
}
public void putNumber(int c) {
number[0] = c;
}
public void putOld() {
if(Arrays.equals(oldNumber, number)) {
System.out.println("Nothing to do!");
return; //How on earth can they literally be the same?!
}
oldNumber = number;
}
public void doWTF() {
putNumber(1);
putOld(); // Works.
putNumber(2); // Expected Result: number = 2; oldNumber = 1 [NOPE] number = 2; oldNumber = 2
putOld(); // [NOPE] Simply Skips with "Nothing to do"
putNumber(3); // Same odd behaviour
putOld(); // Aaaand skips again.
}
}
After calling putNumber the first time, using putNumber again simultaneously puts the value in both variables (oldNumber and Number) instead of only in number[0].
I continued to simplify my code as far as possible so this example is more hands-on. Obviously, the real example where I found this had arrays longer than a single element.
I also tested it with multidimensional arrays, as well as object arrays. No change in the behavior.
I am completely puzzled now and have absolutely no idea how to go on. If you can shed any light on this topic, please do so. I am more than confused.
The following assignment statement:
oldNumber = number;
makes oldNumber and number point to the same underlying array. Perhaps what you want is to make a copy:
System.arraycopy(number, 0, oldNumber, 0, number.length);
See the documentation for System.arraycopy for full details.
This line isn't doing what you think it's doing.
oldNumber = number;
It isn't copying the contents of one array to another. It is making the reference variable oldNumber refer to the same array object as number refers to.
oldNumber ----> [1]
number -------^
So, any change through either variable writes through to the same array, and the change is visible through both references, which refer to the same array.
Then later you call Arrays.equals with references to the same array, so they are "equal".
You want to copy the number with this line instead:
oldNumber[0] = number[0];
When you assign
oldNumber = number
you don't make a copy of the values in the array. oldNumber will point to the exact same array (and future changes in either variable reflect in the other).
You can make a copy with
oldNumber = Arrays.copyOf(number, number.length);
In the putOld function you assigned the reference of the first array to the other. After the first call oldNumber is a pointer to number and if you change a value in one, the other one is affected too.
If you want to copy the values System.arraycopy().
i have an array of strings which i want to convert to int, pretty simple and straightforward here is the code :
public static void main(String[] args) {
String myarray[]=readfile("[pathtothefile]");
int mynums[] = new int[myarray.length];
for (int i=0;i<myarray.length;i++){
mynums[i]=Integer.parseInt(myarray[i]);
}
System.out.print(Arrays.toString(mynums));
}
But the Problem here is, if i initialize "mynums" like this: mynums[]=null; i get NullPointerException on the following line:
"mynums[i]=Integer.parseInt(myarray[i]);"
what i have to do to solve it is
int mynums[] = new int[myarray.length];
here someone explained why it happens but i dont know how to initialize now! i mean sometimes i dont know how big my array can get and i just want to initialize it. is it even possible?
In Java everything is a pointer behind the scenes. So when you do mynums[]=null, you are pointing to a null. So what is null[i]? That is where your NPE comes from. Alternatively when you point it to an array, then you are actually accessing the i'th element of the array.
You have to first initialize the array because it allocates memory depending on the array size. When you want to add for example an integer to an array it writes the int into previously allocated memory.
The memory size won't grow bigger as you add more items.( Unless you use Lists or Hashmaps, ... but it's not true for generic arrays)
If you don't know how big your array will be, consider using SparseIntArray. which is like Lists and will grow bigger as you add items.
Briefly, in java an array is an object, thus you need to treat it like an object and initialize it prior to doing anything with it.
Here's an idea. When you're initializing something as null, you're simply declaring that it exists. For example ... if I told you that there is a dog, but I told you nothing about it ... I didn't tell you where it was, how tall it was, how old, male/female, etc ... I told you none of its properties or how to access it, and all I told you was that there IS a dog (whose name is Array, for sake of argument), then that would be all you know. There's a dog whose name is Array and that is it.
Typically, arrays are used when the size is already known and generally the data is meant to be immutable. For data that are meant to be changed, you should use things like ArrayList. These are intended to be changed at will; you can add/remove elements at a whim. For more information about ArrayList, read up on the links posted above.
Now, as for your code:
public static void main(String[] args) {
ArrayList<int> myInts = new ArrayList<int>();
// define a new null arraylist of integers.
// I'm going to assume that readfile() is a way for you get the file
// into myarray. I'm not quite sure why you would need the [], but I'll
// leave it.
String myarray[] = readfile("[pathtothefile]");
for (int i = 0; i < myarray.length; i++) {
//adds the value you've specifed as an integer to the arraylist.
myInts.add(Integer.parseInt(myarray[i]));
}
for (int i = 0; i < myInts.size(); i++) {
//print the integers
System.out.print(Integer.toString(myInts.get(i)));
}
}
What if you don't use an array but an ArrayList? It grows dynamically as you add elements.