Code A works well, I think Code B can work correctly, but in fact, Code B doesn't work correctly. Why?
Why can't I create an object in the function- private void SetField(Context mContext,MAtt aField,String name) ?
Code A
public class MURLPar {
public MAtt diskcount=new MAtt();
public MAtt diskindex=new MAtt();
public MURLPar(Context mContext){
SetField(mContext,diskcount,"Pardiskcount");
SetField(mContext,diskindex,"Pardiskindex");
}
public class MAtt {
public String name;
public String value;
}
private void SetField(Context mContext,MAtt aField,String name){
int id = mContext.getResources().getIdentifier(name, "string", mContext.getPackageName());
aField.name=mContext.getString(id);
}
}
Code B
public class MURLPar {
public MAtt diskcount;
public MAtt diskindex;
public MURLPar(Context mContext){
SetField(mContext,diskcount,"Pardiskcount");
SetField(mContext,diskindex,"Pardiskindex");
}
public class MAtt {
public String name;
public String value;
}
private void SetField(Context mContext,MAtt aField,String name){
aField=new MAtt(); //Create object
int id = mContext.getResources().getIdentifier(name, "string", mContext.getPackageName());
aField.name=mContext.getString(id);
}
}
Because aField gets new memory address when you use the command aField=new MAtt();
As a result memory address of diskcount and diskindex remain uninitialized.
For more check here: https://stackoverflow.com/a/73021/3923800
What's happening in code B is that the MURLPar constructor passes a reference to diskcount/diskindex to SetField, which within that method has the name aField.
You then reassign aField with a reference to a newly created object, and you then manipulate that object. Note that aField is now referring to a completely separate object, and not whatever it was referring to when you entered SetField.
If you're familiar with C you can think of what you're doing here as something along these lines:
void SetField(MAtt *aField) {
aField = (MAtt*) calloc(1, sizeof(MAtt));
}
MAtt *diskcount;
SetField(diskcount);
And then expecting diskcount to have changed after the call to SetField, which it obviously won't have.
If you want something like an out parameter, you can simulate that by returning a newly created object:
private MAtt SetField(Context mContext, String name){
MAtt aField = new MAtt(); //Create object
int id = mContext.getResources().getIdentifier(name, "string", mContext.getPackageName());
aField.name=mContext.getString(id);
return aField;
}
And then:
diskcount = SetField(mContext, "Pardiskcount");
Related
I noticed a scenario today. When we pass a parameter on private methods, the entity will return the revised values but not primitives.
Here is my sample code,
/**
* #author gowthami
*
*/
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
String s = "gowth";
System.out.println("before " + s);
concateMe(s, "ami");
System.out.println("after " + s);
BeanTest bt = new BeanTest();
bt.setId("1");
System.out.println("before");
System.out.println(bt.getId());
System.out.println(bt.getName());
setBeanTestName(bt, "gowthami");
System.out.println("after");
System.out.println(bt.getId());
System.out.println(bt.getName());
String st = new String("gowth");
System.out.println("before " + st);
concateMe(st, "ami");
System.out.println("after " + st);
}
private static void setBeanTestName(BeanTest bt, String string) {
bt.setName(string);
}
private static void concateMe(String s, String string) {
s = s+string;
System.out.println("inside method " + s);
}
}
BeanTest.java
public class BeanTest {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
So the bean is getting updated even though we are not returning it from private method but a string is not. Can someone explain me whats happening on JVM level?
This is because Java follows Call by value, not Call by reference.
When you are passing s you are actually passing value of s, not the actual s. So though you are changing s in concateMe(), it will not change in your main method.
When you are passing bt, then the change is affecting as you are changing the field variable of that reference. But if you change the reference, then there will be no effect. You can add this in main method:
System.out.println("before......");
System.out.println(bt.getId());
System.out.println(bt.getName());
changeBeanTest(bt);
System.out.println("after");
System.out.println(bt.getId());
System.out.println(bt.getName());
Suppose your changeBeanTest is like this:
private static void changeBeanTest(BeanTest tempBeanTest) {
BeanTest bt = new BeanTest();
bt.setId("2");
bt.setName("Trump");
tempBeanTest = bt;
}
run this. There will be no change to bt sent from main().
The Bean is a full object in java passed by reference to the private method so it is the same instance in the main method and the private method.
You are modifying the values of that instance so the changes show up in both places.
The string is more or less a primitive and passed as a copy of the value instead of the exact instance from main. It is a new instance in the private method and so you are modifying a new variable. The changes don't show up in the main method as it is a different entity.
String s = "gowth"; in this line s is pointing to "gowth" from String Pool.When you are calling
private static void concateMe(String s, String string) here String s is different from caller method String s.Here String s scope is local to method ContactMe,But contactMe local String s pointing same "gowth" which is pointed by Caller class String s.After s = s + string;since String is immutable the method local reference String s pointing a different String "gowthami",but caller method String s is still pointing to "gowth".So you are getting this output.
But in case of Bean both the object pointing same String reference,Once we made any change in reference it would be reflected for both object.
I am struggling with making this code work. Here is my code. First class:
public class PersonalAccount extends Account{
private String cardNumber;
private String cardType;
public ArrayList<PersonalAccount> personalAccounts;
public int personal;
private PersonalAccount(String first, String last, String accountNumber, String cardNumber, String cardType){
super(first, last, accountNumber);
this.cardNumber = "";
this.cardType = "";
}
public void addPersonalAccount(PersonalAccount aPersonalAccount){
personalAccounts.add(aPersonalAccount);
}
public void getNumberOfPersonalAccounts(){
personal = personalAccounts.size();
}
public void listAccounts(){
for (PersonalAccount personalaccount : personalAccounts){
System.out.println("Personal Accounts");
System.out.println(personalaccount);
}
}
public void findAccount(){
int index = 0;
boolean found = false;
while(index < personalAccounts.size() && !found){
PersonalAccount personalaccount = personalAccounts.get(index);
if (personalaccount.getaccountNumber().equals(accountNumber)){
found = true;
}else{
index++;
}
}
}
}
When attempting to create an instance of this class in another class, it instead creates an instance of the PersonalAccount object. Is there a way around this issue? I am very new to Java and BlueJ it should be noted.
EDIT: sorry I should clarify. I'm trying to call the methods from this class in another class. But when declaring
PersonalAccount class1 = new PersonalAccount();
I get the error: constructor PersonalAccount in class PersonalAccount cannot be applied to given types.
I am trying to call the method on a button click (where numAcc is the button):
numAcc.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
int personal;
personal = class1.getNumberOfPersonalAccounts();
}
});
You dont have a default constructor so you cannot create a PersonalAccount like this:
PersonalAccount class1 = new PersonalAccount();
You have to pass the parameters first, last, accountNumber, cardNumber, cardType. It should be something like this:
PersonalAccount class1 = new PersonalAccount("FirstName", "Last_Name", "123456", "123456789", "Visa");
Read this: http://www.dummies.com/how-to/content/how-to-use-a-constructor-in-java.html
You don't have a zero-argument constructor for PersonalAccount which is why the given statement would fail.
Is that the problem you are having?
The problem is here that the constructor is private:
private PersonalAccount(String first, String last, String accountNumber, String cardNumber, String cardType)
Two things:
You need to change your constructor such that it is public so that it is accessible:
public PersonalAccount(String first, String last, String accountNumber, String cardNumber, String cardType)
The next thing is to supply parameters such as first, last, accountNumber etc. However, if you declare: public PersonalAccount(), then you would not need to supply arguments when you instantiate the class.
You should now be able to call the methods of this class!
My data model is as follow:
public class CustomerObject implements Serializable
{
public Integer pkid;
public String code;
public String name;
public CustomerObject()
{
pkid = new Integer(0);
code = "";
name = "";
}
}
Now I am calling this from another class:
public CustomerObject getCustObj() {
CustomerObject custObj = new CustomerObject();
custObj.pkid = new Integer(1001);
custObj.code = "CUST1001";
return custObj;
}
Now here in getCustObj() function I want to pass only pkid and code. I mean I want to remove the variable "name" from the object and then pass. So my passing object will look like:
CustomerObject()
{
pkid = 1000;
code = CUST1001;
}
Please help how I can do this.
Actually I have a data model of 200 variable. I will pass this using webservice. But during pass by webservice I may need only 20 to pass. So I want to reduce the data size.
Use another constructor in class CustomerObject as following.
public class CustomerObject implements Serializable
{
public Integer pkid;
public String code;
public String name;
public CustomerObject()
{
pkid = new Integer(0);
code = "";
name = "";
}
public CustomerObject(int inPkid, String inCode)
{
this.pkid = inPkid;
code = inCode;
}
}
When you call getCustomerObject method from another class use as follows
public CustomerObject getCustObj() {
CustomerObject custObj = new CustomerObject(new Integer(1001),"CUST1001");
}
If you are not setting name in your object, then it is as good as object not having name because name is null. You can't remove name variable from the object.
But if you really want to do so, you can use inheritance. Make one class with all attributes except name and other class extends the first class and adds name attribute to it. So now you can use first class when you don't need the name attribute.
I have this code which gets info from an other class but I have to add another line other code for every instance object.
public static int giveShipData(String shipName,int Data){
if(shipName.equals("Player")){i = Player.getData(Data);}
return i;
}
Is it possible to have something like:
public static int giveShipData(String shipName,int Data){
i = shipName.getData(Data);
return i;
}
Sorry if I am using the wrong terminology I am self taught and new.
I think you'd better to reconsider your design. If you have a ship name and ship data I assume you must have a Ship class which looks something like this:
public class Ship {
private String name;
private int data;
public Ship(String name, int data) {
this.name = name;
this.data = data;
}
public String getName() {
return name;
}
public int getData() {
return data;
}
}
Besides this class there should be a class like Shipyard:
public class Shipyard {
private Map<String, Ship> shipsByNameMap = new HashMap<String, Ship>();
public void registerShipByName(String name, Ship ship){
shipsByNameMap.put(name, ship);
}
public Ship getShipByName(String name){
return shipsByNameMap.get(name);
}
}
So, at first you invoke shipyard.getShip("Player") method to get ship object, than you can invoke ship.getData() method to retrieve ship data.
You might be able to do something like this...
int[] ships = new int[3]; // 3 ships
public void populateShips(){
for (int i=0;i<ships.length;i++){
ships[i] = giveShipData(shipname,data);
}
}
public int giveShipData(String shipName,int data){
return shipName.getData(data);
}
This would allow you to create any number of ships, just increase the size of the ships[] array to be however many ships you want.
Is this kinda what you're after?
As per your code "shipName" is a string...and it does not have getData() method. And why are you passing Data to the getData()... You could instead write something like this-
i = ClassObj.getData(shipname);
and in the method getData return the info regarding the "shipname".
I have encountered a weird problem in my app (java).
I have an enum. Something like that
public enum myEnum implement myIntrface{
valueA(1),valueb(2),valuec(3),valued(4)
private int i;
// and then - a constructor
public MyEnum(int number){
i = number;
}
private MyObj obj = new MyObj;
// getter and setter for obj
}
and in another class I have this
MyEnum.valueA.setObj(new Obj(...))
in briefe - I have an enum with a private instance member that has a set and a get.
So far so good -
The only thing that amazes me is that later on I look at the value of the MyEnum.valueA().obj is null.
there is nothing that updates the value to null, I have even gave it a default value in the constructor and I still see it null later.
any suggestions?
Enums should be un-modifiable classes so you shouldn't really be doing this. If your looking to modify the state of a type based object like an enum you should use an final class approach with embedded constants. Below is an example of a class based approach with a modifiable name an a un-modifiable name...
public final class Connection {
public static final Connection EMAIL = new Connection("email");
public static final Connection PHONE = new Connection("phone");
public static final Connection FAX = new Connection("fax");
/**/
private final String unmodifiableName; //<-- it's final
private String modifiableName;
/*
* The constructor is private so no new connections can be created outside.
*/
private Connection(String name) {
this.unmodifiableName = name;
}
public String getUnmodifiableName() {
return unmodifiableName;
}
public String getModifiableName() {
return modifiableName;
}
public void setModifiableName(String modifiableName) {
this.modifiableName = modifiableName;
}
}
The purpose of enums is to represent constant values. It does not make any sense to set the fields of a constant value.
You should declare your fields as final, and use the constructor to initialize all of them.
For reference, the following code works as expected:
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.get()); // prints "null"
MyEnum.valueA.set(new Integer(42));
System.out.println(MyEnum.valueA.get()); // prints "42"
}
}
the cause of this problem is the db40 framework . It loads an enum from the db using reflection. This is well documented .
http://developer.db4o.com/Forums/tabid/98/aft/5439/Default.aspx