I would like to call up an Method for a library like:
%nameofbookvar%.islend();
but the user should assign the nameofbookvar to the book he wants. So I want java to know that nameofbookvar is a variable and not the name of the object.
How can I do this?
Thanks!!:)
That's something really weird to do on Java because you normally won't create variables like %nameofbookvar% without... defining its name, correct?
For a simple name/value pair, you can use a HashMap:
Map<String, Book> library = new HashMap<String, Book>();
library.put("Frankenstein", new Book("Frankenstein"));
// ....
Book userSearchedBook = library.get("Frankenstein");
userSearchedBook.isLend();
Of course, you'll need a Book class:
public class Book {
private final String title;
private boolean lend;
public Book(String title) {
this.title = title;
}
//...
public boolean isLend() {
return isLend;
}
}
You can store all the books in the library in a Map where the key is the name of the book the user wants and the mapped value is the Book object that belongs to the book in question. For different types of Maps refer to the Implementing Classes in the Map specification and determine which works best for your needs.
public class Library {
private HashMap<String, Book> collection;
public Library() {
collection = new HashMap<>();
}
public Book getBook(String name) {
return collection.get(name);
}
public void addBook(String name, Book book) {
collection.put(name, book);
}
}
public class Book {
private boolean isLend;
public boolean isLend() {
return isLend;
}
}
You can then call the following on a Library object
Library library = new Library(); // Don't forget to add books
library.getBook(%nameofbookvar%).isLend();
Book variable = BookStore.get(theBookTheUserWants);
variable.isLend();
Related
So I'm making a plugin and I want to put two ArrayList (of two different teams) to one Hashmap, so I can get both of the teams in this method:
public static Teams getTeam(Player player) {
if (!hasTeam(player))
return null;
return zombiesTeam.get(player) && survivorsTeam.get(player);
}
Here is the two ArrayList and a Hashmap that I want to have:
public static HashMap<zombiesTeam, survivorsTeam> playerTeams = new HashMap<zombiesTeam, survivorsTeam>();
public static ArrayList<Player> zombiesTeam = new ArrayList<Player>();
public static ArrayList<Player> survivorsTeam = new ArrayList<Player>();
P.S. I know that this code isn't correct
Please ask me for any further additional information
Thanks in advance.
You should do something like this:
public static HashMap<String, ArrayList<Player>> playerTeams = new HashMap<>();
playerTeams.put("zombies", zombiesTeam);
playerTeams.put("survivors", survivorsTeam );
If you want to represent all your "teams" by a hashmap from the team name to the list of team members, I would suggest this:
// In the same class where zombiesTeam and survivorsTeam are declared
public static Map<String, List<Player>> getTeamsByName() {
Map<String, List<Player>> teamsByName = new HashMap<>();
teamsByName.put("zombiesTeam", zombiesTeam);
teamsByName.put("survivors", survivorsTeam);
return teamsByName;
}
However, be sure that you need to use static fields and methods. Your model doesn't suggest this.
For instance, you could rather declare a Team class and a Player class. Since you already have the Player class, here is how I would make the Team class:
public class Team {
private String name;
private Set<Player> teamMembers = new HashSet<>();
public Team(String name) {
this.name = name;
}
public String getName() {
return this.teamName;
}
public Set<Player> getTeamMembers() {
return this.teamMembers;
}
public addPlayer(Player player) {
this.teamMembers.add(player);
}
public removePlayer(Player player) {
this.teamMembers.remove(player);
}
public reset() {
this.teamMembers.clear();
}
}
Be sure to override equals and hashcode for HashSet and HashMap to work correctly. More information about this here:https://www.geeksforgeeks.org/equals-hashcode-methods-java/
I have two classes in java: Movie and Book (it's a simplified example):
Book can have author:
public class Book {
public String author;
public Book(String a) {
this.author = a;
}
public String getAuthor(){
return author;
}
}
And Movie can have title:
public class Movie {
public String title;
public Movie(String t) {
this.title = t;
}
public String getAuthor(){
return title;
}
}
I'm trying to put all objects in a list like this:
ArrayList myList = new ArrayList();
Book book = new Book("William");
Movie movie = new Movie("Titanic");
myList.add(book);
myList.add(movie);
And afterwards I want to count how many books written by John do I have (or any other specific titles). However I can't apply getAuthor() or getTitle() method since java doesn't know what type of object it is
int counter = 0;
for (int i =0;i<myList.size();i++){
if (myList.get(i).getAuthor().equals("John") ){
counter +=1;
}
I would be able to use if clause, check every time for an object type, and apply different methods for different objects, but this is not viable, since in real-life case I have 20+ classes and it would make code very long and maintainable.
Can someone suggest a solution for this? Thanks in advance!
create an interface
public interface HasAuthor {
String getAuthor();
}
implement this interface in both your classes and use this:
List<HasAuthor> list = new ArrayList<>();
list.add(new Book());
list.add(new Movie());
long count = list.stream().filter(smth -> "John".equals(smth.getAuthor())).count();
You cannot be using ArrayList myList = new ArrayList(); in 2017. The world has moved on from that archaic and error-prone style of programming. Generics were added to the Java programming language in 2004, and since then, any attempt to use a generic class without a generic type argument issues a warning. Which brings me to the next issue:
You cannot be ignoring warnings in 2017. Actually, there was never a good time to be ignoring warnings. Your IDE ought to be issuing warnings when you try to do ArrayList myList = new ArrayList(); heed them.
So, bottom line is, you should not be putting books and movies in the same collection. If you have a book class that has an author, and a movie class that has a director, (I will ignore your example of movies having a title and returning that as "author", because it is nonsensical,) then you can have either an interface or an abstract base class called, say, Item, with a String getAuthor() method, which is implemented (overridden) in both Book and Movie.
Then, your myList will be an ArrayList<Item>, and since Item has a getAuthor() method, you will be able to do myList.get( 0 ).getAuthor() and it will work without having to know whether it is a book or a movie.
First, myList.get(i).getAuthor() == "John" won't work since strings need to be compared via equals() (look up tutorials on why).
Second, you need to know the type of your objects and cast accordingly in order to call a method (you could do without the cast using reflection but please don't try that at home). Thus when iterating over your list you need to check:
for (Object o : myList ) {
if (o instanceof Book && ((Book)o).getAuthor().equals("John") ){
counter +=1;
}
}
However, if you want one list to contain all books and movies you'd better provide a common interface or superclass:
//Make it abstract to not allow instances of this class directly
abstract class PieceOfArt {
private String creator;
public String getCreator() {
return creator;
}
}
class Book extends PieceOfArt {
//Access the creator as the author
//note that I do this just for demonstration purposes, just using getCreator() would be perfectly fine
public String getAuthor() {
return getCreator();
}
}
class Movie extends PieceOfArt {
//Access the creator as the director
//note that I do this just for demonstration purposes, just using getCreator() would be perfectly fine
public String getDirector() {
return getCreator();
}
}
List<PieceOfArt> myList = ...;
for( PieceOfArt p : myList ) {
if( p.getCreator().equals("John") {
...
}
}
Putting objects of different, unrelated types, such as Book and Movie, which don't have a common superclass (besides java.lang.Object) is bad practice.
You could define a common abstract superclass for these types, and then create a List of that type. For example:
public abstract class Product {
private String title;
private String author;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
class Book extends Product {
}
class Movie extends Product {
}
Create a List<Product> and work with that:
List<Product> products = new ArrayList<>();
Book book = new Book();
book.setTitle("Cooking");
book.setAuthor("Bob the Cook");
products.add(book);
Movie movie = new Movie();
movie.setTitle("Romance at sea");
movie.setAuthor("John");
products.add(movie);
int count = 0;
for (Product product : products) {
if (product.getAuthor().equals("John")) {
count++;
}
}
NOTE: Do not make the getAuthor method actually return the title in case of a Movie, that would make your program really confusing.
I have a Book class:
public class Book extends SugarRecord {
private String mBookName;
private String mAuthorName;
private List<Page> mPageList;
public Book() {
}
public Book(String bookname, String authorName) {
mBookName = bookname;
mAuthorName = authorName;
mPageList = new ArrayList<>();
}
public String getAuthorName() {
return mAuthorName;
}
public void setAuthorName(String authorName) {
mAuthorName = authorName;
}
public String getBookName() {
return mBookName;
}
public void setBookName(String bookName) {
mBookName = bookName;
}
public void addPage(Page page) {
mPageList.add(page);
}
}
and the Page class:
public class Page extends SugarRecord {
private String mText;
public Page() {
}
public Page(String text) {
mText = text;
}
public String getText() {
return mText;
}
public void setText(String text) {
mText = text;
}
}
I am testing it with this:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Book book = new Book("Some Book Title", "John Doe");
Page page1 = new Page("Once upon a time there was a very lonely bunny who wanted some friends.");
Page page2 = new Page("So he found some friends, and everyone was happy.");
Page page3 = new Page("The end!");
book.addPage(page1);
book.addPage(page2);
book.addPage(page3);
book.save();
}
}
However it is not working as expected. It is trying to make mPageList its own column with this .schema:
CREATE TABLE BOOK ( ID INTEGER PRIMARY KEY AUTOINCREMENT , M_AUTHOR_NAME TEXT, M_BOOK_NAME TEXT, M_PAGE_LIST );
What I'd really like it to do is not treat the list as its own column but instead save the Pages to the PAGE table, with additional ids that reference this Book class (so what I am expecting is something like ID, BOOK_ID, M_TEXT). In short, persistence operations that cascade through nested child objects.
Can this be done in SugarORM?
No ORM database(SugarORm, DBFLow etc) supports List column. As you know sql don't have this datatype as well.
That's the reason why you are getting this error. If you ask me how you are saving list to ORM. I use Gson.
Declare Pagelist as string.
String Pagelist;
Before saving it to database convert it to Json string with the help Gson library.
Gson gson = new Gson();
String value = gson.toJson(your_page_list);
when retrieving from database convert the json string to List using Gson.
List<Page> page_list;
Type typeIndicatorForGson = new TypeToken<ArrayList<Page>>() {}.getType();
Gson myGson = new Gson();
page_list = myGson.fromJson(page_json_data_from_database, typeIndicatorForGson);
No List<Object> available on SugarORM. The way you can manage this is a little tricky. In few words, you can manage 1 to N relations, upside down. Take a look to the next example
Lets suppose a Team object which can have N Person objects. Normally you will use a List<Person> in your class Team in this way:
public class Team {
String teamName;
List<Person>
...
}
public class Person {
String name;
String rol;
...
}
Well, it is not possible on SugarORM. But you can add Team as a property in Person, so, any Person's instance should contain a reference to the Team object it belong.
public class Team extends SugarRecord<Team> {
String teamName;
...
}
public class Person extends SugarRecord<Person> {
String name;
String rol;
Team team;
...
}
Then you can get all the Person objects from Team with a method (in the Team class) like:
public class Team extends SugarRecord<Team> {
String teamName;
...
public List<Person> getPersons(){
return Person.find(Person.class, "id = ?", String.valueOf(this.getId()));
}
}
So, you can manage 1 to N relations, but you can't manage N to M relationships (Person belonging to more than one Team object).
IMO the way to manage this is using an Associative Entity in order to split N to M into two 1 to N relationships.
As you can see SugarORM is not allowing you to think just in terms of objects, but, any case you can save a lot of boiler plate coding.
CLARIFICATION:
I do not know the objects name. That is where the problem comes in. I am creating an object like such:
`new Object(String attributes);
I am trying to run code in another class such as:
***.getStuff();
the trick to it is, there is no name for the Object. but i do know what String attributes is
The question: Is there any way to accomplish this without using the dreaded for loop?
This question is a bit tricky to word, but I will try my best. What I want to is get an object that matches a particular field without making a messy for loop. Something along the lines of:
Object A has the field String name.
String nameObj = "Tickle";
Object A has the name "Tickle"
if(nameObj.equals(Object A)){
//bla bla
}
Very confusing wording, yes. Sorry about that. I want to use Object A in my code without having to figure out which object it is, assuming all I have is its name. I am looking for a shortcut around using a for loop, I suppose.
Feel free to ask questions about what I am looking for. Sorry about the terribly worded question.
Poor coding, but this is what I am looking for...
nameObj.getName().getObjectA();
If you have a bunch of objects with names, and you want to grab an object by its name, I suggest you look up the class HashMap. HashMap lets you put in objects under keys, and when you give the hash map a key it returns the object associated with that key. So in your example, the keys would be string names.
Take at this implementation, that demonstrates what #Patashu said, create a map to the objects, in this case I just add an abstract class at the top of all.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
Factory.add(new NiceGuy("first one"));
Factory.add(new FirstChild("ok im late"));
System.out.println(Factory.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
}
public String getId(){
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}
class Factory {
private static HashMap allTheObjects = new HashMap();
public static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}
This is another version, of the same implementation with a more transparent aproach, without the Factory class, the Parent itself will keep track of the instances and save in a list.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
NiceGuy foo = new NiceGuy("first one");
FirstChild bar = new FirstChild("ok im late");
System.out.println(ParentOfAll.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
add(this);
}
public String getId() {
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
private static HashMap allTheObjects = new HashMap();
private static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}
Problem Description
I have an abstract Paper class that contains common properties of all papers and one or more child classes of paper that add additional information for that type of paper. I then have a HashMap<String, Paper> to store multiple papers.
My application allows the user to update a paper by providing a the pid and then supplying the attributes and values to update. The issue I am having is how do I update the properties on the sub classes when all I have is the super class.
What is the best way/practice to handle this situation?
Class Structure
public abstract class Paper {
String pid;
String title;
String author;
}
public class Publication extends Paper {
int pages;
}
public class PHDThesis extends Paper {
String supervisor;
}
My Current Attempt
This is what I currently have** and it works by using instance of; but I feel there should be a better way to do this.
import java.util.*;
public class App {
public static abstract class Paper {
private String title;
private String author;
public Paper(String title, String author) {
this.title = title;
this.author = author;
}
public void update(String title, String author) {
this.title = title;
this.author = author;
}
}
public static class Publication extends Paper {
private int pages;
public Publication(int pages, String title, String author) {
super(title, author);
this.pages = pages;
}
public void update(String title, String author, int pages) {
super.update(title, author);
this.pages = pages;
}
}
public static class PHDThesis extends Paper {
private String supervisor;
public PHDThesis(String supervisor, String title, String author) {
super(title, author);
this.supervisor = supervisor;
}
public void update(String title, String author, String supervisor) {
super.update(title, author);
this.supervisor = supervisor;
}
}
public static void main(String[] args) {
HashMap<String, Paper> papers = new HashMap<String, Paper>();
papers.put("P001", new PHDThesis("My Super", "My PHD Title", "My Author"));
papers.put("P002", new Publication(22, "My Pub Title", "My Author"));
Paper p = papers.get("P001");
if (p instanceof PHDThesis) {
((PHDThesis)p).update("New Title", "New author", "New Super");
} else if (p instanceof Publication) {
((Publication)p).update("New Title", "New author", 33);
}
}
}
** reduced test code, actual code is much more complex and better laid out.
You can create an object called UpdateBundle with getters for each attribute.
Then the Paper class will have a method update(UpdateBundle) which each child will implement differently.
All you have to do is call that method for each child and they will know how to handle it.
On a separate note, i don't see why the paper class is abstract. You seem to have no abstract methods in it.
public abstract class Paper {
String pid;
String title;
String author;
public void update(PaperUpdateBundle bundle)
{
pid = bundle.getPID();
title = budnle.getTitle();
author = bundle.getAuthor();
}
}
public class Publication extends Paper {
int pages;
public void update(PaperUpdateBundle bundle)
{
super.update(bundle);
pages = bundle.getPages();
}
}
public class PHDThesis {
String supervisor;
public void update(PaperUpdateBundle bundle)
{
super.update(bundle);
supervisor = bundle.getSupervisor();
}
}
public interface PaperUpdateBundle
{
String getPID();
String getTitle();
String getAuthor();
int getPages();
String getSupervisor();
}
Create a method
public void update( Map<String, Object> parameters );
to all Papers and pull the relevant properties from it in the Paper implementations.
In Publication it might look like:
public void update( Map<String, Object> parameters ) {
super.update( parameters );
this.pages = parameters.get( "pages" );
}
The problem with the accepted answer is that it requires you to update all of the properties manually. If the list of properties changes, you have to change the update() method or things will get out of sync. In my experience this happens frequently. And then you've got to spend a lot of time trying to track down the bug.
A different way (I won't call it a "better" way) is to use reflection or some third party library to copy the fields. There are some tradeoffs, though. The advantage is that your code requires a lot less work and will (probably) have fewer bugs. The downside is that your code will be slower, less flexible, and lack compile-time checks.
I have sometimes used Jackson's ObjectMapper.convertValue() to do this. You can find other ways to do it here: Copy all values from fields in one class to another through reflection.