Between Java and Python, which one is better to learn first and why?

Python.

Python.

Don’t even think about it to select another language as your first. Why? Well,

  • Python is easy. Trust me on this one. My first major language was C++ and it lead me to contemplating a career change. Here’s a short snipped of C++ code for displaying “Hello world” on the screen -
#include <iostream>
using namespace std;
int main()
{
	cout << "Hello world!" << endl;
	return 0;
}

Here’s the same thing in Python

print("Hello world!")
  • Python is dynamically typed. What in the world is that? Okay, so computers are dumb. They aren’t smart enough to know that 1
  • 1 is a number, or specifically, an integer and that “hello” is a word or “string” in computer talk. So because of that some programming languages needed to specify the kind of stuff they were working with. For example if you needed to add two numbers in Java, here’s what you’ll have to do -
class AddNums(){
	public static void main(String args[]){
		int first = 1;
		int second = 2;
		int sum = first + second;
		System.out.println(sum);
	}
}

You see that “int” keyword? That stands for “integer” and that basically just tells the computer, “Hey, I need something to store this number but since you’re too stupid to know that it’s a number I’ve specified it and so you should remember that the variable called “first” can only store integer values and I’ve given it the value of 1

1. And so on with “second” and “sum””. That’s what’s up with Java. In Python?

first = 1
second = 2
sum = first + second
print(sum)

Do you see how clean that is? Notice the serene absence of semi colons.

  • Python supports all styles of programming. Okay, this might be a little controversial but it still worth mentioning. Broadly, there are two methods (no pun intended) of programming - object oriented and procedural. I’m not going to get into details but, long story short, they’re both great ways of approaching problems but Object Oriented is better suited for large scale projects and will, if done right (a huge deal in itself), be cleaner. Procedural is better for small projects to get things, just, done. For example -
class Hello{
	public static void main(String args[]){
		System.out.println("Hello world!");
	}
}

vs

def main():
	print("Hello world!")
main()
  • Now both Python and Java support OOP (object oriented programming) but Java forces it upon you by giving you no other way out. That, for big companies and large scale projects, might be a good thing but for someone who doesn’t even know what a class is can be a big hassle. Python, on the other hand, lets you do your own thing. Again, this might be a bad thing but it’ll all depend on the kind of practices you pick up and follow. Ruby is another language and it is very similar to Python but I don’t like it as much because it’s way more lenient on coders. Python kind of maintains that fine line. But yes, for a beginner, Object Oriented might feel forced if all you need to do is write something to take in two numbers and print their sum but in the long, really long run, it could be a good thing.
  • Python is used almost everywhere. Web development? Check. Penetration testing? Check. Making awesome games? Check. Glue code for projects not native-ly written in Python? Check. Maching Learning? Double check that boy! Scientific research? Check. Academics? Check. Android apps and other scale-able projects…? Java is your thing. Native programming is one place where Python fails.


And I think that’s about it. Both languages are great in their own thing and what they’re used for but Python, hands down, is one of the best things a beginner could start with today.

Python vs Java: Understand Object Oriented Programming

Python vs Java: Understand Object Oriented Programming

This article compares and contrasts object-oriented programming support in Python vs Java. By the end, you’ll be able to apply your knowledge of object-oriented programming to Python, understand how to reinterpret your understanding of Java objects to Python, and use objects in a Pythonic way.

Java programmers making a move to Python often struggle with Python’s approach to object-oriented programming (OOP). The approach to working with objects, variable types, and other language capabilities taken by Python vs Java are quite different. It can make switching between both languages very confusing.

Over the course of this article, you’ll:

  • Build a basic class in both Java and Python
  • Explore how object attributes work in Python vs Java
  • Compare and contrast Java methods and Python functions
  • Discover inheritance and polymorphism mechanisms in both languages
  • Investigate reflection across Python vs Java
  • Apply everything in a complete class implementation in both languages

This article isn’t a primer on object-oriented programming. Rather, it compares object-oriented features and principles of Python vs Java. Readers should have good knowledge of Java, and also be familiar with coding Python.

Table of Contents

  • Sample Classes in Python vs Java
  • Object Attributes
    Declaration and InitializationPublic and PrivateAccess Controlself and this* Methods and Functions
  • Inheritance and Polymorphism
    InheritanceTypes and PolymorphismDefault MethodsOperator Overloading* Reflection
    Examining an Object’s TypeExamining an Object’s AttributesCalling Methods Through Reflection* Conclusion
Sample Classes in Python vs Java

To begin, you’ll implement the same small class in both Python and Java to illustrate the differences between them. You’ll make modifications to them as the article progresses.

First, assume you have the following Car class definition in Java:

public class Car {
    private String color;
    private String model;
    private int year;
    public Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }
    public String getColor() {
        return color;
    }
    public String getModel() {
        return model;
    }
    public int getYear() {
        return year;
    }
}

Java classes are defined in files with the same name as the class. So, you have to save this class in a file named Car.java. Only one class can be defined in each file.

A similar small Car class is written in Python as follows:

class Car:
    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year

In Python you can declare a class anywhere, in any file, at any time. Save this class in the file car.py.

Using these classes as your base, you can explore the basic components of classes and objects.

Object Attributes

All object oriented languages have some way to store data about the object. In **Java **and Python, data is stored in attributes, which are variables associated with specific objects.

One of the most significant differences between Python vs Java is how they define and manage class and object attributes. Some of these differences come from constraints imposed by the languages, while others come from best practices.

Declaration and Initialization

In Java, you declare attributes in the class body, outside of any methods, with a definite type. You must define class attributes before they are used:

public class Car {
    private String color;
    private String model;
    private int year;

In Python, you both declare and define attributes inside the class <strong>init</strong>(), which is the equivalent of Java’s constructor:

def __init__(self, color, model, year):
    self.color = color
    self.model = model
    self.year = year

By prefixing the variable names with self, you tell Python these are attributes. Each instance of the class will have a copy. All variables in Python are loosely typed, and these attributes are no exception.

You can also create instance variables outside of .<strong>init</strong>(), but it’s not a best practice as their scope is often confusing. If not used properly, instance variables created outside of .__init__() can lead to subtle bugs that are hard to find. For example, you can add a new attribute .wheels to a Car object like this:

>>> import car
>>> my_car = car.Car("yellow", "beetle", 1967)
>>> print(f"My car is {my_car.color}")
My car is yellow
>>> my_car.wheels = 5
>>> print(f"Wheels: {my_car.wheels}")
Wheels: 5

However, if you forget the my_car.wheels = 5 on line 6, then Python displays an error:

>>> import car
>>> my_car = car.Car("yellow", "beetle", 1967)
>>> print(f"My car is {my_car.color}")
My car is yellow
>>> print(f"Wheels: {my_car.wheels}")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute 'wheels'

In Python, when you declare a variable outside of a method, it’s treated as a class variable. Update the Car class as follows:

class Car:
    wheels = 0
    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year

This changes how you use the variable wheels. Instead of referring to it using an object, you refer to it using the class name:

>>> import car
>>> my_car = car.Car("yellow", "beetle", 1967)
>>> print(f"My car is {my_car.color}")
My car is yellow
>>> print(f"It has {car.Car.wheels} wheels")
It has 0 wheels
>>> print(f"It has {my_car.wheels} wheels")
It has 0 wheels

Note: In Python, you refer to a class variable using the following syntax:

  1. The name of the file containing the class, without the .py extension
  2. A dot
  3. The name of the class
  4. A dot
  5. The name of the variable

Since you saved the Car class in the file car.py, you refer to the class variable wheels on line 6 as car.Car.wheels.

You can refer to my<em>car.wheels or car.Car.wheels, but be careful. Changing the value of the instance variable my</em>car.wheels will not change the value of the class variable car.Car.wheels:

>>> from car import *
>>> my_car = car.Car("yellow", "Beetle", "1966")
>>> my_other_car = car.Car("red", "corvette", "1999")
>>> print(f"My car is {my_car.color}")
My car is yellow
>>> print(f"It has {my_car.wheels} wheels")
It has 0 wheels
>>> print(f"My other car is {my_other_car.color}")
My other car is red
>>> print(f"It has {my_other_car.wheels} wheels")
It has 0 wheels
>>> # Change the class variable value
... car.Car.wheels = 4
>>> print(f"My car has {my_car.wheels} wheels")
My car has 4 wheels
>>> print(f"My other car has {my_other_car.wheels} wheels")
My other car has 4 wheels
>>> # Change the instance variable value for my_car
... my_car.wheels = 5
>>> print(f"My car has {my_car.wheels} wheels")
My car has 5 wheels
>>> print(f"My other car has {my_other_car.wheels} wheels")
My other car has 4 wheels

You define two Car objects on lines 2 and 3:

  1. my_car
  2. my_other_car

At first, both of them have zero wheels. When you set the class variable using car.Car.wheels = 4 on line 16, both objects now have four wheels. However, when you set the instance variable using my_car.wheels = 5 on line 24, only that object is affected.

This means that there are now two different copies of the wheels attribute:

  1. A class variable that applies to all Car objects
  2. A specific instance variable applicable to the my_car object only

It isn’t difficult to accidentally refer to the wrong one and introduce subtle bugs.

Java’s equivalent to a class attribute is a static attribute:

public class Car {
    private String color;
    private String model;
    private int year;
    private static int wheels;

    public Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }

    public static int getWheels() {
        return wheels;
    }

    public static void setWheels(int count) {
        wheels = count;
    }
}

Normally, you refer to static variables using the Java class name. You can refer to a static variable through a class instance like Python, but it’s not a best practice.

Your Java class is getting long. One of the reasons why Java is more verbose than Python is the notion of public and private methods and attributes.

Public and Private

Java controls access to methods and attributes by differentiating between public data and private data.

In Java, it is expected that attributes are declared as private, or protected if subclasses need direct access to them. This limits access to these attributes from code outside the class. To provide access to private attributes, you declare public methods which set and retrieve data in a controlled manner (more on that later).

Recall from your Java class above that the color variable was declared as private. Therefore, this Java code will show a compilation error at the highlighted line:

Car myCar = new Car("blue", "Ford", 1972);

// Paint the car
myCar.color = "red";

If you don’t specify an access level, then the attribute defaults to package protected, which limits access to classes in the same package. You have to mark the attribute as public if you want this code to work.

However, declaring public attributes is not considered a best practice in Java. You’re expected to declare attributes as private, and use public access methods, such as the .getColor() and .getModel() shown in the code.

Python doesn’t have the same notion of private or protected data that Java does. Everything in Python is public. This code works with your existing Python class just fine:

>>> my_car = car.Car("blue", "Ford", 1972)

>>> # Paint the car
... my_car.color = "red"

Instead of private, Python has a notion of a non-public instance variable. Any variable which starts with an underscore character is defined to be non-public. This naming convention makes it harder to access a variable, but it’s only a naming convention, and you can still access the variable directly.

Add the following line to your Python Car class:

class Car:

    wheels = 0

    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year
        self._cupholders = 6

You can access the ._cupholders variable directly:

>>> import car
>>> my_car = car.Car("yellow", "Beetle", "1969")
>>> print(f"It was built in {my_car.year}")
It was built in 1969
>>> my_car.year = 1966
>>> print(f"It was built in {my_car.year}")
It was built in 1966
>>> print(f"It has {my_car._cupholders} cupholders.")
It has 6 cupholders.

Python lets you access ._cupholders, but IDEs such as VS Code may issue a warning through linters that support PEP 8.

Here’s the code in VS Code, with a warning highlighted and displayed:

Python further recognizes using double underscore characters in front of a variable to conceal an attribute in Python. When Python sees a double underscore variable, it changes the variable name internally to make it difficult to access directly. This mechanism avoids accidents but still doesn’t make data impossible to access.

To show this mechanism in action, change the Python Car class again:

class Car:

    wheels = 0

    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year
        self.__cupholders = 6

Now, when you try to access the .__cupholders variable, you see the following error:

>>> import car
>>> my_car = car.Car("yellow", "Beetle", "1969")
>>> print(f"It was built in {my_car.year}")
It was built in 1969
>>> my_car.year = 1966
>>> print(f"It was built in {my_car.year}")
It was built in 1966
>>> print(f"It has {my_car.__cupholders} cupholders.")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute '__cupholders'

So why doesn’t the .__cupholders attribute exist?

When Python sees an attribute with double underscores, it changes the attribute by prefixing the original name of the attribute with an underscore, followed by the class name. To use the attribute directly, you need to change the name you use as well:

>>> print(f"It has {my_car._Car__cupholders} cupholders")
It has 6 cupholders

When you use double underscores to conceal an attribute from the user, Python changes the name in a well-documented manner. This means that a determined developer can still access the attribute directly.

So if your Java attributes are declared private, and your Python attributes are prefaced with double underscores, then how do you provide and control access to the data they store?

Access Control

In Java, you access private attributes using setters and getters. To allow users to paint their cars, add the following code to your Java class:

public String getColor() {
    return color;
}

public void setColor(String color) {
    this.color = color;
}

Since .getColor() and .setColor() are public, anyone can call them to change or retrieve the car’s color. Java’s best practices of using private attributes accessed with public getters and setters is one of the reasons why Java code tends to be more verbose than Python.

As you saw above, you access attributes directly in Python. Since everything is public, you can access anything at any time from anywhere. You set and get attribute values directly by referring to their names. You can even delete attributes in Python, which isn’t possible in Java:

>>> my_car = Car("yellow", "beetle", 1969)
>>> print(f"My car was built in {my_car.year}")
My car was built in 1969
>>> my_car.year = 1966
>>> print(f"It was built in {my_car.year}")
It was built in 1966
>>> del my_car.year
>>> print(f"It was built in {my_car.year}")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute 'year'

However, there are times you may want to control access to an attribute. In that case, you can use Python properties.

In Python, properties provide controllable access to class attributes using Python decorator syntax. Properties allow functions to be declared in Python classes that are analogous to Java getter and setter methods, with the added bonus of allowing you to delete attributes as well.

You can see how properties work by adding one to your Car class:

class Car:
    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year
        self._voltage = 12
    @property
    def voltage(self):
        return self._voltage

    @voltage.setter
    def voltage(self, volts):
        print("Warning: this can cause problems!")
        self._voltage = volts

    @voltage.deleter
    def voltage(self):
        print("Warning: the radio will stop working!")
        del self._voltage

Here, you expand the notion of the Car to include electric vehicles. You declare the ._voltage attribute to hold the battery voltage on line 6.

To provide controlled access, you define a function called voltage() to return the private value on lines 9 and 10. By using the @property decoration, you mark it as a getter that anyone can access directly.

Similarly, you define a setter function on lines 13 to 15, also called voltage(). However, you decorate this function with @voltage.setter. Lastly, you use @voltage.deleter to decorate a third voltage() on lines 18 to 20, which allows controlled deletion of the attribute.

The names of the decorated functions are all the same, indicating they control access to the same attribute. The function names also become the name of the attribute you use to access the value. Here’s how these properties work in practice:

>>> from car import *
>>> my_car = Car("yellow", "beetle", 1969)
>>> print(f"My car uses {my_car.voltage} volts")
My car uses 12 volts
>>> my_car.voltage = 6
Warning: this can cause problems!
>>> print(f"My car now uses {my_car.voltage} volts")
My car now uses 6 volts
>>> del my_car.voltage
Warning: the radio will stop working!

Note that you use .voltage in the highlighted lines above, not ._voltage. This tells Python to use the property functions you defined:

  • When you print the value of my_car.voltage on line 4, Python calls .voltage() decorated with @property.
  • When you assign a value to my_car.voltage on line 7, Python calls .voltage() decorated with @voltage.setter.
  • When you delete my_car.voltage on line 13, Python calls .voltage() decorated with @voltage.deleter.

The @property, @.setter, and @.deleter decorations make it possible to control access to attributes without requiring users to use different methods. You can even make attributes appear to be read-only properties by omitting the @.setter and @.deleter decorated functions.

self and this

In Java, a class refers to itself with the this reference:

public void setColor(String color) {
    this.color = color;
}

this is implicit in Java code: it doesn’t normally need to be written, unless there may be confusion between two variables with the same name.

You can write the same setter this way:

public void setColor(String newColor) {
    color = newColor;
}

Since Car has an attribute named .color, and there isn’t another variable in scope with the same name, a reference to that name works. We used this in the first example to differentiate between the attribute and parameter both named color.

In Python, the keyword self serves a similar purpose. It’s how you refer to member variables, but unlike Java’s this, it’s required if you want to create or refer to a member attribute:

class Car:
    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year
        self._voltage = 12

    @property
    def voltage(self):
        return self._voltage

Python requires each self in the code above. Each one either creates or refers to the attributes. If you omit them, then Python will create a local variable instead of an attribute.

The difference between how you use self and this in Python and Java is due to underlying differences between the two languages and how they name variables and attributes.

Methods and Functions

This difference between Python vs Java is, simply put, that Python has functions, and Java doesn’t.

In Python, the following code is perfectly fine (and very common):

>>> def say_hi():
...     print("Hi!")
... 
>>> say_hi()
Hi!

You can call say_hi() from anywhere it’s visible. This function has no reference to self, which indicates that it’s a global function, not a class function. It can’t alter or store any data in any classes but can use local and global variables.

In contrast, every line of Java code you write belongs to a class. Functions can’t exist outside of a class, and by definition, all Java functions are methods. In Java, the closest you can get to a pure function is by using a static method:

public class Utils {
    static void SayHi() {
        System.out.println("Hi!");
    }
}

Utils.SayHi() is callable from anywhere without first creating an instance of Utils. Since you can call SayHi() without creating an object first, the this reference doesn’t exist. However, this is still not a function in the sense that say_hi() is in Python.

Inheritance and Polymorphism

Inheritance and polymorphism are two fundamental concepts in object-oriented programming.

Inheritance allows objects to derive attributes and functionality from other objects, creating a hierarchy moving from more general objects to more specific. For example, a Car and a Boat are both specific types of Vehicles. Objects can inherit their behavior from a single parent object or multiple parent objects, and are referred to as child objects when they do.

Polymorphism allows two or more objects to behave like one another, which allows them to be used interchangeably. For example, if a method or function knows how to paint a Vehicle object, then it can also paint a Car or Boat object, since they inherit their data and behavior from the Vehicle.

These fundamental OOP concepts are implemented quite differently in Python vs Java.

Inheritance

Python supports multiple inheritance, or creating classes that inherit behavior from more than one parent class.

To see how this works, update the Car class by breaking it into two categories, one for vehicles, and one for devices that use electricity:

class Vehicle:
    def __init__(self, color, model):
        self.color = color
        self.model = model

class Device:
    def __init__(self):
        self._voltage = 12

class Car(Vehicle, Device):
    def __init__(self, color, model, year):
        Vehicle.__init__(self, color, model)
        Device.__init__(self)
        self.year = year

    @property
    def voltage(self):
        return self._voltage

    @voltage.setter
    def voltage(self, volts):
        print("Warning: this can cause problems!")
        self._voltage = volts

    @voltage.deleter
    def voltage(self):
        print("Warning: the radio will stop working!")
        del self._voltage

A Vehicle is defined as having .color and .model attributes. Then, a Device is defined to have a ._voltage attribute. Since the original Car object had these three attributes, it can be redefined to inherit both the Vehicle and Device classes. The color, model, and _voltage attributes will be part of the new Car class.

In the .__init__() for Car, you call the .__init__() methods for both of the parent classes to make sure everything is initialized properly. Once done, you can add any other functionality you want to your Car. In this case, you add a .year attribute specific to Car objects, and getter and setter methods for .voltage.

Functionally, the new Car class behaves as it always has. You create and use Car objects just as before:

>>> from car import *
>>> my_car = Car("yellow", "beetle", 1969)

>>> print(f"My car is {my_car.color}")
My car is yellow

>>> print(f"My car uses {my_car.voltage} volts")
My car uses 12 volts

>>> my_car.voltage = 6
Warning: this can cause problems!

>>> print(f"My car now uses {my_car.voltage} volts")
My car now uses 6 volts

Java, on the other hand, only supports single inheritance, which means classes in Java can inherit data and behavior from only a single parent class. However, Java objects can inherit behavior from many different interfaces. Interfaces provide a group of related methods an object must implement, and allow multiple child classes to behave similarly.

To see this in action, split the Java Car class into a parent class and an interface:

public class Vehicle {

    private String color;
    private String model;

    public Vehicle(String color, String model) {
        this.color = color;
        this.model = model;
    }

    public String getColor() {
        return color;
    }

    public String getModel() {
        return model;
    }
}

public interface Device {
    int getVoltage();
}

public class Car extends Vehicle implements Device {

    private int voltage;
    private int year;

    public Car(String color, String model, int year) {
        super(color, model);
        this.year = year;
        this.voltage = 12;
    }

    @Override
    public int getVoltage() {
        return voltage;
    }

    public int getYear() {
        return year;
    }
}

Remember that each class and interface needs to live in its own file.

As you did with Python, you create a new class called Vehicle to hold the more general vehicle related data and functionality. However, to add the Device functionality, you need to create an interface instead. This interface defines a single method to return the voltage of the Device.

Redefining the Car class requires you to inherit from Vehicle using extend, and implement the Device interface using implements. In the constructor, you call the parent class constructor using the built-in super(). Since there is only one parent class, it can only refer to the Vehicle constructor. To implement the interface, you write getVoltage() using the @Override annotation.

Rather than getting code reuse from Device as Python did, Java requires you to implement the same functionality in every class that implements the interface. Interfaces only define the methods—they cannot define instance data or implementation details.

So why is this the case for Java? It all comes down to types.

Types and Polymorphism

Java’s strict type checking is what drives its interface design.

Every class and interface in Java is a type. Therefore, if two Java objects implement the same interface, then they are considered to be the same type with respect to that interface. This mechanism allows different classes to be used interchangeably, which is the definition of polymorphism.

You can implement device charging for your Java objects by creating a .charge() that takes a Device to charge. Any object that implements the Device interface can be passed to .charge(). This also means that classes that do not implement Device will generate a compilation error.

Create the following class in a file called Rhino.java:

public class Rhino {
}

Now you can create a new Main.java to implement .charge() and explore how Car and Rhino objects differ:

public class Main{
    public static void charge(Device device) {
       device.getVoltage();
    }

    public static void main(String[] args) throws Exception {
        Car car = new Car("yellow", "beetle", 1969);
        Rhino rhino = new Rhino();
        charge(car);
        charge(rhino);
    }
}

Here is what you should see when you try to build this code:

Information:2019-02-02 15:20 - Compilation completed with 
    1 error and 0 warnings in 4 s 395 ms
Main.java
Error:(43, 11) java: incompatible types: Rhino cannot be converted to Device

Since the Rhino class doesn’t implement the Device interface, it can’t be passed into .charge().

In contrast to Java’s strict variable typing, Python uses a concept called duck typing, which in basic terms means that if a variable “walks like a duck and quacks like a duck, then it’s a duck.” Instead of identifying objects by type, Python examines their behavior.

You can explore duck typing by implementing similar device charging capabilities for your Python Device class:

>>> def charge(device):
...     if hasattr(device, '_voltage'):
...         print(f"Charging a {device._voltage} volt device")
...     else:
...         print(f"I can't charge a {device.__class__.__name__}")
... 
>>> class Phone(Device):
...     pass
... 
>>> class Rhino:
...     pass
... 
>>> my_car = Car("yellow", "Beetle", "1966")
>>> my_phone = Phone()
>>> my_rhino = Rhino()

>>> charge(my_car)
Charging a 12 volt device
>>> charge(my_phone)
Charging a 12 volt device
>>> charge(my_rhino)
I can't charge a Rhino

charge() must check for the existence of the ._voltage attribute in the object it’s passed. Since the Device class defines this attribute, any class that inherits from it (such as Car and Phone) will have this attribute, and will therefore show they are charging properly. Classes that do not inherit from Device (like Rhino) may not have this attribute, and will not be able to charge (which is good, since charging rhinos can be dangerous).

Default Methods

All Java classes descend from the Object class, which contains a set of methods every other class inherits. Subclasses can either override them or keep the defaults. The Object class defines the following methods:

class Object {
    boolean equals(Object obj) { ... }    
    int hashCode() { ... }    
    String toString() { ... }    
}

By default, <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-" target="_blank">equals()</a> compares the addresses of the current Object with a second Object passed in, and <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--" target="_blank">hashcode()</a> computes a unique identifier that also uses the address of the current Object. These methods are used in many different contexts in Java. For example, utility classes, such as collections that sort objects based on value, need both of them.

<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#toString--" target="_blank">toString()</a> returns a String representation of the Object. By default, this is the name of the class and the address. This method is called automatically when an Object is passed to a method that requires a String argument, such as System.out.println():

Car car = new Car("yellow", "Beetle", 1969);
System.out.println(car);

Running this code will use the default .toString() to show the car object:

[email protected]

Not very useful, right? You can improve this by overriding the default .toString(). Add this method to your Java Car class:

public String toString() {
    return "Car: " + getColor() + " : " + getModel() + " : " + getYear();
}

Now, when you run the same sample code, you’ll see the following:

Car: yellow : Beetle : 1969

Python provides similar functionality with a set of common dunder (short for “double underscore”) methods. Every Python class inherits these methods, and you can override them to modify their behavior.

For string representations of an object, Python provides __repr__() and __str__(), which you can learn about in Pythonic OOP String Conversion: __repr__ vs __str__. The unambiguous representation of an object is returned by __repr__(), while __str__() returns a human readable representation. These are roughly analogous to .hashcode() and .toString() in Java.

Like Java, Python provides default implementations of these dunder methods:

>>> my_car = Car("yellow", "Beetle", "1966")

>>> print(repr(my_car))
<car.Car object at 0x7fe4ca154f98>
>>> print(str(my_car))
<car.Car object at 0x7fe4ca154f98>

You can improve this output by overriding .__str__(), adding this to your Python Car class:

def __str__(self):
    return f'Car {self.color} : {self.model} : {self.year}'

This gives you a much nicer result:

>>> my_car = Car("yellow", "Beetle", "1966")

>>> print(repr(my_car))
<car.Car object at 0x7f09e9a7b630>
>>> print(str(my_car))
Car yellow : Beetle : 1966

Overriding the dunder method gave us a more readable representation of your Car. You may want to override the .__repr__() as well, as it is often useful for debugging.

Python offers a lot more dunder methods. Using dunder methods, you can define your object’s behavior during iteration, comparison, addition, or making an object callable directly, among other things.

Operator Overloading

Operator overloading refers to redefining how Python operators work when operating on user-defined objects. Python’s dunder methods allow you to implement operator overloading, something that Java doesn’t offer at all.

Modify your Python Car class with the following additional dunder methods:

class Car:
    def __init__(self, color, model, year):
        self.color = color
        self.model = model
        self.year = year

    def __str__(self):
        return f'Car {self.color} : {self.model} : {self.year}'

    def __eq__(self, other):
        return self.year == other.year

    def __lt__(self, other):
        return self.year < other.year

    def __add__(self, other):
        return Car(self.color + other.color, 
                   self.model + other.model, 
                   int(self.year) + int(other.year))

The table below shows the relationship between these dunder methods and the Python operators they represent:

When Python sees an expression containing objects, it calls any dunder methods defined that correspond to operators in the expression. The code below uses these new overloaded arithmetic operators on a couple of Car objects:

>>> my_car = Car("yellow", "Beetle", "1966")
>>> your_car = Car("red", "Corvette", "1967")

>>> print (my_car < your_car)
True
>>> print (my_car > your_car)
False
>>> print (my_car == your_car)
False
>>> print (my_car + your_car)
Car yellowred : BeetleCorvette : 3933 

There are many more operators you can overload using dunder methods. They offer a way to enrich your object’s behavior in a way that Java’s common base class default methods don’t.

Reflection

Reflection refers to examining an object or class from within the object or class. Both Java and Python offer ways to explore and examine the attributes and methods in a class.

Examining an Object’s Type

Both languages have ways to test or check an object’s type.

In Python, you use type() to display the type of a variable, and isinstance() to determine if a given variable is an instance or child of a specific class:

>>> my_car = Car("yellow", "Beetle", "1966")

>>> print(type(my_car))
<class 'car.Car'>
>>> print(isinstance(my_car, Car))
True
>>> print(isinstance(my_car, Device))
True

In Java, you query the object for its type using .getClass(), and use the instanceof operator to check for a specific class:

Car car = new Car("yellow", "beetle", 1969);

System.out.println(car.getClass());
System.out.println(car instanceof Car);

This code outputs the following:

class com.realpython.Car
true

Examining an Object’s Attributes

In Python, you can view every attribute and function contained in any object (including all the dunder methods) using dir(). To get the specific details of a given attribute or function, use getattr():

>>> print(dir(my_car))
['_Car__cupholders', '__add__', '__class__', '__delattr__', '__dict__', 
 '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
 '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
 '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
 '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
 '_voltage', 'color', 'model', 'voltage', 'wheels', 'year']

>>> print(getattr(my_car, "__format__"))
<built-in method __format__ of Car object at 0x7fb4c10f5438>

Java has similar capabilities, but the language’s access control and type safety make it more complicated to retrieve.

.getFields() retrieves a list of all publicly accessible attributes. However, since none of the attributes of Car are public, this code returns an empty array:

Field[] fields = car.getClass().getFields();

Java treats attributes and methods as separate entities, so public methods are retrieved using .getDeclaredMethods(). Since public attributes will have a corresponding .get method, one way to discover if a class contains a specific property might look like this:

  • Use .getFields() to generate an array of all the methods.
  • Loop through all the methods returned:
  • For each method discovered, return true if the method:
    Begins with the word get OR accepts zero argumentsAND doesn’t return voidAND includes the name of the propertyOtherwise, return false.
    Here’s a quick-and-dirty example:
public static boolean getProperty(String name, Object object) throws Exception {
    Method[] declaredMethods = object.getClass().getDeclaredMethods();
    for (Method method : declaredMethods) {
        if (isGetter(method) && 
            method.getName().toUpperCase().contains(name.toUpperCase())) {
              return true;
        }
    }
    return false;
}
// Helper function to get if the method is a getter method
public static boolean isGetter(Method method) {
    if ((method.getName().startsWith("get") || 
         method.getParameterCount() == 0 ) && 
        !method.getReturnType().equals(void.class)) {
          return true;
    }
    return false;
}

getProperty() is your entry point. Call this with the name of an attribute and an object. It returns true if the property is found, and false if not.

Calling Methods Through Reflection

Both Java and Python provide mechanisms to call methods through reflection.

In the Java example above, instead of simply returning true if the property was found, you could call the method directly. Recall that getDeclaredMethods() returns an array of Method objects. The Method object itself has a method called .invoke(), which will call the Method. Instead of returning true when the correct method is found on line 7 above, you can return method.invoke(object) instead.

This capability exists in Python as well. However, since Python doesn’t differentiate between functions and attributes, you have to look specifically for entries that are callable:

>>> for method_name in dir(my_car):
...     if callable(getattr(my_car, method_name)):
...         print(method_name)
... 
__add__
__class__
__delattr__
__dir__
__eq__
__format__
__ge__
__getattribute__
__gt__
__init__
__init_subclass__
__le__
__lt__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__

Python methods are simpler to manage and call than in Java. Adding the () operator (and any required arguments) is all you need to do.

The code below will find an object’s .__str__() and call it through reflection:

>>> for method_name in dir(my_car):
...     attr = getattr(my_car, method_name)
...     if callable(attr):
...         if method_name == '__str__':
...             print(attr())
... 
Car yellow : Beetle : 1966

Here, every attribute returned by dir() is checked. You get the actual attribute object using getattr(), and check if it’s a callable function using callable(). If so, you then check if its name is __str__(), and then call it.

Conclusion

Throughout the course of this article, you learned how object-oriented principles differ in Python vs Java. As you read, you:

  • Built a basic class in both Java and Python
  • Explored how object attributes work in Python vs Java
  • Compared and contrasted Java methods and Python functions
  • Discovered inheritance and polymorphism mechanisms in both languages
  • Investigated reflection across Python vs Java
  • Applied everything in a complete class implementation in both languages

Understanding the differences in Python vs Java when handling objects, and the syntax choices each language makes, will help you apply best practices and make your next project smoother.

So Sánh Python với Java Qua Ví dụ

So Sánh Python với Java Qua Ví dụ

Bạn phân vân không biết nên học Python hay Java? Bạn muốn biết đâu là ngôn ngữ lập trình phù hợp nhất với bạn? Đây là câu trả lời!

Bạn phân vân không biết nên học Python hay Java? Bạn muốn biết đâu là ngôn ngữ lập trình phù hợp nhất với bạn? Đây là câu trả lời!

Python vs Java: Which is best? Code examples and comparison for 2019

Python vs Java: Which is best? Code examples and comparison for 2019

Should you choose Java or Python for your next project? Are you fortunate enough to have a choice? Are one of these languages a better option?

Should you choose Java or Python for your next project? Are you fortunate enough to have a choice? Are one of these languages a better option?

According to GitHub’s annual Octoverse report, Java and Python are the second and third most popular languages for the fourth year in a row. According to the same story, Python is one of the top ten fastest growing languages. Most of the other fast-gainers are new languages, while Python has been around longer than Java.

At the time of writing, the TIOBE index places Java at the top of their list and Python at number three. Python moved up a spot this month (December 2018), after sitting at number four for over a year.

Digital Ocean’s recent language survey places Python at number two on their list of languages for open source projects. Java is in fourth place, with only half the adoption of Python.

So, the two languages are popular and aren’t going anywhere. Which one is your best choice?

Java vs. Python in 2019

Java and Python have many similarities. Both languages have strong cross-platform support and extensive standard libraries. They both treat (nearly) everything as objects. Both languages compile to bytecode, but Python is (usually) compiled at runtime. They are both members of the Algol family, although Python deviates further from C/C++ than Java does.

Support for Python 2.x will end on January 1, 2020. For a long time, Python development has fragmented between version 2.7 and the regular releases of new 3.x versions. But, with the end-of-life date for Python 2 a year away, the question over which version to use is settled. The community has centered on Python 3.

Meanwhile, Oracle’s new release model for Java created a lot of fear, uncertainty, and doubt in the software community. Even though the announcement provided a free (as in beer) option and a clear upgrade path, confusion continues to reign. Several platforms providers, such as Red Hat and Amazon, have stepped in to support OpenJDK. But the once unified Java community is more fragmented than Python ever was. Let’s take a closer look at the similarities and differences between Java vs. Python.

Java vs. Python typing

Python and Java are both object-oriented languages, but Java uses static types, while Python is dynamic. This is the most significant difference and affects how you design, write, and troubleshoot programs in a fundamental way. Let’s look at two code examples.

First, in Python, we’ll create an array with some data in it, and print it to the console.

stuff = ["Hello, World!", "Hi there, Everyone!", 6]
for i in stuff:
    print(i)

Next, let’s try it in Java.

public class Test {
    public static void main(String args[]) {
        String array[] = {"Hello, World", "Hi there, Everyone", "6"};
        for (String i : array) {
          System.out.println(i);
        }
    }
}

In Python, we put two strings and an integer in the same array, and then printed the contents. For Java, we declared a List of Strings and put three string values in it.

We can’t mix types in a Java array. The code won’t compile.

 String array[] = {"Hello, World", "Hi there, Everyone", 6};

We could declare the array as containing Object instead of String, and override Java’s type system. But, that’s not how any experienced Java developer uses the language.

In Python, we don’t have to provide a type when we declare the array and can put whatever we want in it. It’s up to us to make sure we don’t try to misuse the contents.

For example, what if we modified the code above to do this?

stuff = ["Hello, World!", "Hi there, Everyone!", 6]
for i in stuff:
    print(i + " Foobar!")

The above code will throw an error when we try to run it since we can’t append an integer with a string. What are advantages and disadvantages to dynamic typing and static typing?

Static typing catches type errors at compile time. So, if mixing strings and integers weren’t what you wanted to do, the Java compiler catches the mistake. How much of an advantage compile-time checks is up for debate in some circles. But, static typing does enforce a discipline that some developers appreciate.

Whether static typing prevents errors or not, it does make code run faster. A compiler working on statically-typed code can optimize better for the target platform. Also, you avoid runtime type errors, adding another performance boost.

Code that’s written with dynamic types tends to be less verbose than static languages. Variables aren’t declared with types, and the type can change. This saves a copy or type conversion to new variable declarations.

The question of code readability comes up often when debating Java vs. Python. Let’s take a look at that next.

Code readability and formatting

Let’s take an example from Java and Python and compare them. In this example, we need to open a large text file and collect each line into sets of 50 comma-separated records. Here is the Python code:

def get_symbols(file_name):
    with open(file_name, "r") as in_file:
        records = []
        count = 0
        symbol_set = ""
        for line in in_file:
            symbol_set = symbol_set + line[:-1] + ','
            count = count + 1
            if count % 50 == 0:
                records.append(symbol_set)
                symbol_set = ""

        symbols.append(symbol_set)
        return records

Here’s the Java code:

List<String> getSymbols(String filename) throws IOException {
  List<String> records = new ArrayList<>();
  try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
    String line;
    int count = 0;
    StringBuilder symbol_set = new StringBuilder();
    while ((line = reader.readLine()) != null) {
      symbol_set.append(line).append(",");
      count++;
      if ((count % 50) == 0) {
        records.add(symbol_set.toString());
        symbol_set.setLength(0);
      }
    }
    records.add(symbol_set.toString());
    return records;
  }
}

Whitespace

Whitespace is part of Python’s syntax, while Java ignores it. Python uses tabs for nesting and a full colon to start loops and conditional blocks. Java ignores whitespace and uses semicolons, parentheses and curly braces. Arguments over which code is easier to read, like the debate over static vs. dynamic typing, are subjective. Some say Python code is more concise and uniform than Java because your formatting choices are more limited. Python’s use of whitespace ends debates over how to format code. The only option you have left is how to use blank lines.

The Python snippet is a few lines shorter than the Java snippet, a difference that adds up in larger programs. Much of the difference is because there are no closing braces. But Python’s brevity—when compared to Java —goes deeper.

Brevity

Let’s look at how the two languages handle files.

Here’s Python again:

with open(file_name, "r") as in_file:

Here’s Java:

try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {

In both cases, the declaration creates a block. The file resource remains in scope, and the languages close it when the code exits the block.

In Python, we’re opening a file and reading from it. When the loop reaches the end of the file, the loop exits.

for line in in_file:

Java is more complicated. We’re opening a BufferedReader by passing it a FileReader. We consume lines from the reader. It’s our responsibility to check for null when the file ends.

while ((line = reader.readLine()) != null) {

This only demonstrates that it’s easier to handle text files in Python. But, it demonstrates how Java tends to be more verbose than Python. “Pythonic” constructs are more concise and less demanding. Java has evolved over the past few releases, with the introduction of try-with-resources in Java 7 and lambdas in Java 8, but it’s still a verbose language.

Let’s revisit our first example.

Here’s the Python again:

stuff = ["Hello, World!", "Hi there, Everyone!", 6]
    for i in stuff:
        print(i)

Here is the Java:

public class Test {
    public static void main(String args[]) {
        String array[] = {"Hello, World", "Hi there, Everyone", "6"};
        for (String i : array) {
          System.out.println(i);
        }
    }
}

Both of these snippets will build and run as is. Python will run a script from beginning to end of a file. Java requires at least one entry point, a static method named main. The JVM (Java virtual machine) runs this method in the class passed to it on the command line.

Putting together a Python program tends to be faster and easier than in Java. This is especially true of utility programs for manipulating files or retrieving data from web resources.

Performance

Both Java and Python compile to bytecode and run in virtual machines. This isolates code from differences between operating systems, making the languages cross-platform. But there’s a critical difference. Python usually compiles code at runtime, while Java compiles it in advance, and distributes the bytecode.

Most JVMs perform just-in-time compilation to all or part of programs to native code, which significantly improves performance. Mainstream Python doesn’t do this, but a few variants such as PyPy do.

The difference in performance between Java and Python is sometimes significant in some cases. A simple binary tree test runs ten times faster in Java than in Python.

Final thoughts on Java vs. Python

So, which language is your best choice?

Oracle’s new support model changes the Java landscape. While there is still a free option, the new release schedule and support model gives developers a reason to take stock. Java clients will need to pay Oracle for support, change OpenJDK versions on a regular basis, or rely on third parties like Red Hat or Amazon for fixes and security updates.

At the same time, Python has cleared a significant hurdle with Python 3. Python has a more unified support model than Java for the first time, and open source developers are focusing their efforts on the latest version of the language. I have to give Python the edge here.

Whether Python’s dynamic typing is better than Java’s static approach is subjective. The debate between the two models predates both of them, and it’s a question of what’s best for you and your team.

After working on large projects in both languages, I feel secure saying that Python’s syntax is more concise than Java’s. It’s easier to get up and running quickly with a new project in Python than it is in Java. Python wins again.

Performance is where Java has a substantial advantage over Python. Java’s just-in-time compilation gives it an advantage over Python’s interpreted performance. While neither language is suitable for latency-sensitive applications, Java is still a great deal faster than Python.

All things considered, Python’s advantages outweigh the disadvantages. If you’re not already considering it, give it another look.

In any project, whether you choose Python or Java make sure it’s error free with the Raygun Platform. Raygun automatically detects errors and performance problems with sophisticated Error Monitoring, Real User Monitoring, and Application Performance Monitoring.