When most people start Minecraft modding the first thing they do is take an existing class for a Block, Item or Entity and extend it and change a bit of it. This is a great way to start modding because it is an easy to achieve something interesting without understanding all the Minecraft (and Forge and FML) code. However, some people continue to use class extension without understanding the full implication. Perhaps it would have been better to copy the code for the class. So I'd like to educate beginners on the difference.
Definition Of Extending / Inheritance
"Extending" a class means that you've used the extends keyword to create an "inheritance", where the child class by default will behave the same as the parent class. You then @Override the methods to change the behavior where desired.
Important: I highly recommend you study general Java tutorials on inheritance such as Jenkov's Java Inheritance Tutorial.
The idea is common in object-oriented programming and is intended to allow code reuse and help organize object behavior.
For example, in modding you might have a EntityVampire and you might want to create a similar entity that acts the same but has some differences like maybe making a EntityMasterVampire that has more health, has different texture, and drops better loot. That would be a case where you'd probably have EntityMasterVampire extend EntityVampire.
Tip: In your IDE (like Eclipse) you can see the class inheritance by right-clicking on a class and choosing Type Hierarchy.
Using inheritance allows you to build up a "hierarchy" of object behavior, such as how the EntityAgeable adds the ability to have a child entity and EntityTameable adds ability to have an owner.
This is obviously very useful, but if used incorrectly it can cause issues...
When Extending Classes Goes Wrong
Key Point: A class that is extended from a class is also considered to be the parent class.
For example, imagine you want to make a goat entity. You might think that an EntitySheep is pretty close to what you want, so you make your EntityGoat extend EntitySheep. You change the model and texture and everything works great, right? Wrong. Because technically any code that checks for EntitySheep will test true on your entity. For example, because your goat is also a sheep the wolves will attack your goats, your goats will be shearable, and sheep will be able to mate with your goats. Maybe you want your goats to be treated like sheep, but probably not and what if you tried to extend sheep to make a giraffe -- that wouldn't make sense would it?
Conversely, if you want something to be a type of something, go ahead and extend it. Maybe you want to make a "golden ram" entity that is a sheep but gives you a "golden fleece" item. In that case, it would probably make sense to extend a sheep.
Tip: Only extend a class if you want the subclass to be fully treated like the parent class (i.e. you're making an additional type of that class).
Furthermore, in good coding practice (of course there are many points of view about good coding practice) you really shouldn't fully override parent class methods -- the point of "extending" is to add to, not to modify. In a good class hierarchy the parent class would only contain code that is common to all its subclasses. However, since we didn't write the vanilla Minecraft code, we can't always use the hierarchy perfectly so in modding we do sometimes need to extend classes that we then modify. It is still good to strive to a clean inheritance scheme though!
When To Copy A Class' Code
Let's go back to the example of making a giraffe entity. In such a case, it is probably a better idea to copy the code from the EntitySheep into your class and then modify it to suit your needs. You'll notice that the code you copied still extends something: it extends EntityAnimal. That makes sense because you likely do want your giraffe to be considered an animal (in Minecraft being an animal means you can have different ages and they can breed which seems appropriate for a giraffe).
You'll also notice that the code you copied implements the IShearable interface. Since you don't want your giraffe to be shearable, you can just delete that without problem. (You would not have been able to delete that if you had extended EntitySheep because you would inherit the interface and be forced to implement it.)
Key Point: What all this really means is that you should select what you extend to be appropriate to your need, then copy from other subclasses of that parent for anything that might be useful.
Thanks to Boosch for encouraging me to write this section.
Once you extend a class, you probably want to change it somewhat. So you will likely take some of the methods and "override" them. Overriding will cause your new method to be used instead of the parent's method that has the same name and parameter list.
It is considered good practice to annotate methods you're changing with the @Override annotation. This helps your IDE (like Eclipse) warn you if you make a typo mistake where you think you're overriding and are not, or where you don't want to override and you actually are. You should make sure your settings for your IDE include warnings for @Override mistakes.
Now, if you override a method you're probably either trying to add additional functionality to the parent or you're trying to replace the functionality of the parent. If you want to add to it, then you will want to call the "super method" by using super.myMethodName() inside your overriding method.
However, if you're replacing the functionality you generally should not call the super method.
Warning: Only call the super method if you are adding to the functionality, but not if you're trying to change it.
Warning: If you intend to replace the functionality, make sure you understand the functionality you're replacing, especially if the super method also called its own super methods.
Overall, you need to be very careful with overriding methods especially paying attention to how you call super methods.
Using @Override And Super Methods
Thanks to Boosch for encouraging me to write this section.
Once you extend a class, you probably want to change it somewhat. So you will likely take some of the methods and "override" them. Overriding will cause your new method to be used instead of the parent's method that has the same name and parameter list.
It is considered good practice to annotate methods you're changing with the @Override annotation. This helps your IDE (like Eclipse) warn you if you make a typo mistake where you think you're overriding and are not, or where you don't want to override and you actually are. You should make sure your settings for your IDE include warnings for @Override mistakes.
Now, if you override a method you're probably either trying to add additional functionality to the parent or you're trying to replace the functionality of the parent. If you want to add to it, then you will want to call the "super method" by using super.myMethodName() inside your overriding method.
However, if you're replacing the functionality you generally should not call the super method.
Warning: Only call the super method if you are adding to the functionality, but not if you're trying to change it.
Warning: If you intend to replace the functionality, make sure you understand the functionality you're replacing, especially if the super method also called its own super methods.
Overall, you need to be very careful with overriding methods especially paying attention to how you call super methods.
Conclusion
So overall it is pretty simple once you understand it:- If you want something to truly be an additional type of something you should extend it.
- If you want something to be "like" something else you should extend its parent class and copy its code (then modify as needed). Just be careful with how you override and use super calls.
0 comments :
Post a Comment