2

I would like to make a variable that points to whatever a different reference variable is pointing to, so that if I change where the reference variable points, the pointer variable automatically points to that new place, too.

For example, suppose I consider my favourite book to be whatever my local library's favourite book is. If my library changes what their favourite book is, I automatically consider that to be my favourite book.

Here is some code to demonstrate what I mean:

Book littleWomen = new Book("Little Women");
Book dracula = new Book("Dracula");

Book libraryFavourite = litteWomen;
Book myFavourite = libraryFavourite;  //myFavoutie is now littleWomen

libraryFavourite = dracula;   //i want myFavourite to update to point to dracula, now.

In the above code, changing what libraryFavourite points to doesn't automatically change what myFavourite points to. It stays pointing at littleWomen.

I understand why the above code doesn't work as I'm saying I "want" it to. I understand that reference variables hold memory addresses, and therefore myFavourite = libraryFavourite just assigns the memory address that libraryFavourite points to into myFavourite, and thus future changes to libraryFavourite doesn't change myFavourite. I only include the above code to help clarify the behaviour that I want, but understand I'll need a different approach to achieve.

This link talks about aliasing a class (and the answers received was basically that it can't be done). Aliasing isn't exactly what I want done, though, because I want to be free to change myFavourite to stop pointing to the library's favourite book, and instead to something else (such as, for example, some new book that I newly discovered and fell in love with).

Community
  • 1
  • 1
silph
  • 316
  • 2
  • 9
  • 1
    This is deliberately excluded from the language, as in many, many other languages. – user2357112 Oct 28 '14 at 01:04
  • What is your use case? – PM 77-1 Oct 28 '14 at 01:06
  • 1
    This is directly related to [Is Java “pass-by-reference” or “pass-by-value”?](http://stackoverflow.com/q/40480/1065197) – Luiggi Mendoza Oct 28 '14 at 01:10
  • @PM77-1, I was trying to teach another student in my progam the basics of objects and classes, and when we got to examples where I assigned a reference variable to another reference variable, she actually thought that this was how reference variables worked. This intrigued me, because I realized that I didn't know how to make this behaviour happen in Java, though I know it's possible in (say) C. – silph Oct 28 '14 at 01:11
  • You may want to read this: http://javadude.com/articles/passbyvalue.htm – Mik378 Oct 28 '14 at 01:12
  • How is this possible in C? It would mean that if you have two identical pointers and you change the value of one of them, the other is updated as well. – PM 77-1 Oct 28 '14 at 01:14
  • @PM77-1 You can dereference a pointer and assign it a new value or use a double pointer to make it point somewhere else. http://ideone.com/kIimJ3 – Radiodef Oct 28 '14 at 01:33
  • @Radiodef - Yes, you can. How does it apply to the case at hand? – PM 77-1 Oct 28 '14 at 01:57
  • @PM77-1 Dereferencing a pointer and assigning a new value is what you can't do in Java. – Radiodef Oct 28 '14 at 02:00
  • @Radiodef - You are not clear. Assigning new value to what? – PM 77-1 Oct 28 '14 at 02:03

3 Answers3

3

To achieve such behaviour you have to store references in objects instead of local values. It should never work as you're expecting. Variable just points to object, and if you change it you just make it points to different object - you cannot change also root object!

Favorite libraryFavorite = new Favorite(littleWomen);
Favorite myFavorite = libraryFavorite;

libraryFavorite.set(dracula);

//now myFavorite.get also points to dracula

and Favorite is just a reference holder:

public class Favorite {
  private Book book;

  public Favorite(Book book) {
    this.book = book;
  }

  public void set(Book newBook) {
    this.book = newBook;
  }

  public Book get() {
    return book;
  }
}
Jakub Kubrynski
  • 13,724
  • 6
  • 60
  • 85
  • @Quincunx no problem. Also those solutions are quite different - your allow building book trees - I'm not sure it's the best idea in this case. – Jakub Kubrynski Oct 28 '14 at 01:17
  • If I wanted to use libraryFavourite and myFavourite the very same way as Books (so that I could do things like `myFavourite.turnPage()` ), do you recommend that I make `Favourite` a subclass of Book? This workaround seems clunky, but maybe there is no better workaround, so thanks for the suggestion. – silph Oct 28 '14 at 01:20
  • 2
    @silph I think it's bad idea because favorite position is something else than a book. If it simplifies your code than it can be an option but I'll call it more "workaround" than "solution" :) – Jakub Kubrynski Oct 28 '14 at 01:23
  • 2
    @silph Jakub's workaround is better. If you did make favourite a subclass of `Book`, you'd end up with some weird things that can happen. To do `myFavourite.turnPage()`, simply do `myFavourite.get().turnPage()`. For one example of something weird that can happen, what if we do `myFavourite.set(myFavourite)`? – Justin Oct 28 '14 at 01:23
0

There is not way to do that. When you assign a reference (referenceA) to another reference (referenceB). The referenceA copy the memory address of referenceB and that's it. referenceA forget about referenceB. If referenceB point to another memory address, that change doesn't apply to referenceA.

Elvermg
  • 427
  • 6
  • 12
  • Yes, I realize that this is how reference variables work. This is the problem :) I was wondering if there was a different way to approach this (such as maybe some Java feature I'm unaware of, or some clever technique I'm unaware of). – silph Oct 28 '14 at 01:16
0

A workaround would be to let your book class have a constructor that takes another book as an argument, use that the first time you initialize it, then mutate it. Perhaps you'd want a subclass for this, so you could treat the favourite as a Book. I'd actually recommend not doing that, instead have a getter for the book and just do favourite.get().whateverYouWantToDoWithMe();

Then you could do this:

Book littleWomen = new Book("Little Women");
Book dracula = new Book("Dracula");

Book libraryFavourite = new Book(littleWomen);
Book myFavourite = libraryFavourite;  //myFavourite is now littleWomen

libraryFavourite.setBook(dracula); //myFavourite is now dracula

One possible way to implement this while still allowing Book to be immutable is as follows:

public class ReferenceBook extends Book {
    private Book book;

    public ReferenceBook(Book book) {
        this.book = book;
    }
    public void setBook(Book book) {
        this.book = book;
    }
    public boolean equals(Object o){
        if (o instanceof Book) {
            return o.equals(book);
        }
        return false;
    }
    // and so on for other methods
}

Then you'd do this:

Book littleWomen = new Book("Little Women");
Book dracula = new Book("Dracula");

ReferenceBook libraryFavourite = new ReferenceBook(littleWomen);
Book myFavourite = libraryFavourite;  //myFavourite is now littleWomen

libraryFavourite.setBook(dracula); //myFavourite is now dracula
Justin
  • 24,288
  • 12
  • 92
  • 142
  • thank you for writing this; it helps clarify for me why I like @JakubKubrynski's answer, by contrast. I like your way here because I'm able to use `myFavourite` and `libraryFavourite`as `Book`s (ie using methods that `Book`s have), and I like Jakub's answer because it emphasizes the fact that I am intending to use such unusual/strange "pointer" behaviour. – silph Oct 28 '14 at 01:38