Hellooooo🥳️🥳️🥳️I am glad🤗 that you have joined me again in this Android development journey🚀. I am glad that you have decide to join me again on this exciting journey as we explore the world of kotlin for Android development.
🚀Kotlin is a programming language that's gaining popularity due to its ability to combine object-oriented and functional programming paradigms.
🚀In this article, we'll explore Kotlin's object-oriented programming features and how they can be used to build efficient software applications. Whether you're a seasoned developer or just starting out, come with us on this journey to discover why Kotlin is worth learning.
In this article, we are going to deep dive into one of the most important concepts of Kotlin:
1. Functions
2. Classes and Objects
3. Interfaces and Inheritance
4. Class Inheritance
1. Functions
- Functions help in writing the code once and re-using it in other parts of your code.
- Functions are used to break the code into smaller, more understandable, and reusable parts.
Variable scope and local functions
- Variables defined inside of a function are called local variables. They are visible only in their defined scope.
- These variables can be used in the functions they are defined.
fun firstFunction () {
val name = "Google Office Zurich"
println(name)
}
fun CarType () {
val car = "Bently"
firstFunction()
println(car)
}
fun main () {
CarType()
}
The output of the above code after calling the function CarType()
in the main function is Google Zurich Office
and Bently
. firstFunction
cannot be used to access the type of car becaude it is mentioned outside its scope.
- Local functions are defined inside other functions. They can only be used in their scope of the definition.
- Top-level functions do not have such limitations they can be used everywhere even in functions defined earlier in a file.
- Below is an example of a top-level function
fun calculateCircleArea(radius: Double): Double {
return Math.PI * radius * radius
}
fun main () {
val area = calculateCircleArea(2.0)
println("The area of the circle is $area")
}
The output of the above code is 12.566370614359172
Functions with Parameters and result
-
Parameters
are named variables that is defined as part of a function. They are specified using parenthesis after the function name. - When you declare or write a function and you use as a parameter, when you want to call this function, you must supply the parameter with a value. The value supplied for this parameter is called
Argument
fun calculateCircleArea(radius: Double): Double {
return Math.PI * radius * radius
}
fun main () {
val area = calculateCircleArea(2.0)
println("The area of the circle is $area")
}
In the above code sample the name radius: Double
is the parameter of the function calculateCircleArea
. The Argument supplied for the calculateCircleArea
function is 2.0
- An absolete function is a function that returns an integer value without a sign so this doesn't change positive values, but it returns all negative values into positive.
fun absolete(value : Int) :Int {
if(value >= 0){
return value
}else{
return -value
}
}
fun main () {
println(absolete(123)) // output 123
println(absolete(-1)) // output 1
println(absolete(9)) // output 9
}
Single expression functions
- In Kotlin, there is a special syntax for single expressions functions. Instead of braces with the body, you can use the equality sign, which specifies what should be returned.
fun triangleArea(width : Double, height : Double) : Double = width * height/2
fun main () {
val area = triangleArea(12.0,56.0)
println(area)
}
The ouput of the above code is 336.0
Recursion
- These are functions that call themselves.
- A factorial function is an example of a recursive function. To implement such a function we might define a variable called
accumulator
with an initial value of 1, which will be used to accumulate all the numbers. Then, for each number from 1 to the number you calculate the factorial, you will modify the value by multiplying it by the next number. - After that, all you need to do is to return the accumulator variable.
fun factorial(number : Int) : Int {
var accumulator = 1
for(i in 1..number){
accumulator = accumulator * i
}
return accumulator
}
fun main () {
println(factorial(5))
}
Default and Named arguments
- Default arguments that need not specify explicitly while calling a function. When a function is called without passing arguments the parameters become the default arguments.
fun student(name: String="Praveen", standard: String="IX" , roll_no: Int=11) {
println("Name of the student is: $name")
println("Standard of the student is: $standard")
println("Roll no of the student is: $roll_no")
}
fun main() {
student()
}
The output of the above code is Praveen
IX
11
since we have not passed any arguments in our student function in the main function.
- Named arguments allows to specify arguments while calling a function. With named arguments, you can pass arguments to a function in any order, as long as you specify the name of each argument.
fun student( name: String="Praveen", standard: String="IX" , roll_no: Int=11 ) {
println("Name of the student is: $name")
println("Standard of the student is: $standard")
println("Roll no of the student is: $roll_no")
}
fun main(args: Array<String>) {
val name_of_student = "Gaurav"
val standard_of_student = "VIII"
val roll_no_of_student = 25
student(name=name_of_student,roll_no=roll_no_of_student)
}
For this code to work we pass arguments with names as defined in function.
2. Classes and Objects
- A
class
is like a template that defines what an object looks like and how it can be used. - It specifies how the objects should be created and which methods and properties it consists of.
- An
object
is an instance of a class. A type represents a category of objects eg an integer represents all integers. - To define a class in kotlin you use the keyword
class
and specify thename
of the class.
class Car {
var brand = ""
var model = ""
var year = 0
}
- You will realize that when we use curly braces to define a class we must initialize the objects, we cannot leave them open but when we use brackets we don't have to initialize the class we only specify the type.
- When we use brackets to enclose the class we should use commas to separate different properties inside it.
class Car (
var brand : String,
var model : String,
var year : Int
)
Creating an object
- We can create an object of the
Car
class above calledobjCar
, and then we can access the properties of objCar by using the dotsyntax (.)
class Car (
var brand : String,
var model : String,
var year : Int
)
fun main () {
var objCar = Car(
"Bently",
"Mustang",
2013
)
println( objCar.brand)
println( objCar.model)
println( objCar.year)
}
- When we use the brackets to define the class we use the primary constructor property when specifying a value for a regular property.
- When we use the curly braces we define the properties of the class not as parameters as shown below.
class Car {
var brand : String = ""
var model : String = ""
var year : Int = 0
}
fun main () {
var objCar = Car()
objCar.brand = "Bently"
objCar.model = "Mustang"
objCar.year = 2013
println( objCar.brand)
println( objCar.model)
println( objCar.year)
}
- We can also specify the property of a class inside a class body. First, we use curly brackets as shown below.
class Car (
var brand : String,
var model : String
)
{
var ObjCar : String = "$brand($model)"
}
fun main () {
var CarType = Car( brand = "Bently", model = "Mustang")
println(CarType.ObjCar)
}
The output of the above code will be Bently(Mustang)
Methods
- A method is a function associated with a class, for example a defined class. They are defined inside the class body. In other words, they are defined inside the curly braces.
- Methods have direct access to all the properties of a class as shown below
class Subject (val name : String)
{
fun Teacher (course : String, grade : String) : Teaches {
println("$name teaches $course well I got $grade grade")
return Teaches(course,grade)
}
fun TeachesWell (course : String, grade : String){
println("Congratulations")
//Methods can be used to call other methods
Teacher(course, grade)
}
}
class Teaches (
var course : String,
var grade : String
)
fun main () {
val read = Subject ("Daniel")
read.TeachesWell(course = "Physics", grade = "A")
}
- The output of the above code is
Congratulations
Daniel teaches Physics well I got A grade
- In order to call a method, you need to have an object. For instance, when you have a
class Dog
with amethod feed
, to call this method outside the class, you need to first have an object of type Dog.
class Dog (var name: String)
{
var hunger : Int = 62
fun feed (){
println("Feeding $name")
hunger = 0
}
}
fun main () {
var dog = Dog ("Rex")
dog.feed()
}
The output of the above code is feeding Rex
.
- Inside the method, we use the
name
andhunger
properties from the object that was used during the call. In a way, It is similar to definingfeed
as a top-level function and parsingDog
as an argument. - In methods, you can access members implicitly. For instance in the below code use just
name
, notdog.name
class Dog (var name : String)
{
var hunger : Int = 62
}
fun feed (dog : Dog){
println("Feeding ${dog.name}")
dog.hunger = 0
}
fun main () {
var dog = Dog ("Rex")
feed(dog)
}
The output of the above code is feeding Rex
.
- When you call methods, the object of their class is passed to their class body. This is called a receiver.
- A receiver can be accessed using
this keyword
also known as reciever reference. So if you want to reference an object used to call a method inside this method, usethis keyword
.
class Dog(var name : String){
var hunger = 62
fun feed (){
//Receiver
var currentDog : Dog = this
println("Feeding ${currentDog.name}")
currentDog.hunger = 0
}
}
fun main (){
var dog = Dog("Rex")
dog.feed()
}
- when you call methods or properties inside methods, such as when you call name, you are calling methods or properties in the receiver, so its like calling
this.name
class Dog(var name : String){
var hunger = 62
fun feed (){
//Receiver
//var currentDog : Dog = this
println("Feeding ${this.name}")
this.hunger = 0
}
}
fun main (){
var dog = Dog("Rex")
dog.feed()
}
-
this
keyword can be used to call methods or properties and sometimes it can be used explicitly. - One example might be when you have a method parameter and class property with the same name. Like in the below class, there is a property
name
and a methodchangeName
with a parametername
. So if you seename
inside the class, you will have a value of the parameter. To access the property usethis.name
class User (var name : String) {
fun changeName (name : String){
println("Change name from ${this.name} to $name")
this.name = name
}
}
fun main () {
val user = User("Alpha")
user.changeName("Beta")
println(user.name)
}
3. Interfaces and Inheritance
- An interface is a collection of abstract methods and properties that define a common contract for classes that implement the interface.
- Interfaces cannot be instantiated directly.
Creating interfaces
- Interface is defined by the keyword
Interface
followed by the name of the interface and curly braces. - Functions and properties of the interface reside inside the curly braces.
interface Fruit {
fun BitterFruit()
fun SweetFruit()
}
Implementing Interfaces
- Interfaces are implemented by classes or objects.
- Classes or objects implementing the interface should be followed by a colon and the name of the interface which is to be implemented. eg
interface Fruit {
fun BitterFruit()
fun SweetFruit()
}
class TypeFruit: Fruit {
override fun BitterFruit() {
println("Lemon is a bitter fruit")
}
override fun SweetFruit() {
println("Apple is sweet fruit ")
}
}
fun main () {
val fruit = TypeFruit ()
fruit.BitterFruit()
fruit.SweetFruit()
}
- We are using the keyword override in our functions because they were specified in the interface.
Default values and Default methods
- Methods can have default values as parameters which are used when no value is passed during the function call.
interface Sum {
// 10 and 20 are default values
fun add( firstNum : Int = 10,secondNum : Int = 20)
fun output () {
println("This is an example of an addition of numbers")
}
}
class Addition (): Sum {
override fun add (firstNum : Int, secondNum : Int){
val SumOfNumbers = firstNum + secondNum
println("The sum of $firstNum and $secondNum is $SumOfNumbers")
}
override fun output () {
super.output()
println("Sum of two numbers")
}
}
fun main () {
val addition = Addition()
//We are overriding the default values with new arguments
addition.add(30,30)
addition.output()
}
The output is 60
and not 30
. In our main function, we have changed our default values to hold 30
in both firstNum and secondNum.
- The super keyword is used to call the default implementation of print specified in the inheritance.
Inheritance properties in interface
- Interfaces can contain properties that cannot be instantiated hence no backfield to hold their values. The fields in the interface are either left abstract or are provided an implementation.
-Interfaces can also inherit others interfaces adding its own properties and methods in both the interfaces.
- An interface can inherit more than interface.
- The value of
length
andbreadth
are the properties of the interface dimensions.
interface Dimensions {
val length : Double
val breadth : Double
}
interface CalculateParameters : Dimensions {
fun area ()
fun perimeter ()
}
class Calculations () : CalculateParameters {
override val length : Double
get() = 40.0
override val breadth : Double
get() = 60.0
override fun area () {
println("The area is ${length * breadth}")
}
override fun perimeter () {
println("The perimeter is ${2*(length + breadth)}")
}
}
fun main () {
var obj = Calculations ()
// The area is 2400.0
obj.area()
// The perimeter is 200.0
obj.perimeter()
}
- Kotlin has multiple interface implementations. A class can implement more than one interface provided that it has a definition for all the numbers of the interface.
- A class can only inherit one class.
interface Dimensions {
val length : Double
val breadth : Double
}
interface CalculateParameters {
fun area ()
fun perimeter ()
}
class Calculations () : Dimensions, CalculateParameters {
override val length : Double
get() = 40.0
override val breadth : Double
get() = 60.0
override fun area () {
println("The area is ${length * breadth}")
}
override fun perimeter () {
println("The perimeter is ${2*(length + breadth)}")
}
}
fun main () {
var obj = Calculations ()
// The area is 2400.0
obj.area()
// The perimeter is 200.0
obj.perimeter()
}
4. Class Inheritance
- During class inheritance
1. One must define a class that extends from another class.
2. The class to be inherited must be open.
3. One must introduce the same modifications to the behavior.
- When one class inherits from another, it takes all the previous class methods and properties. It becomes its subclass, which means that it can be used wherever its parent is expected.
open class Klass () {
fun students () {
println("There are 50 students in the class")
}
fun subject () {
println("The class takes chemistry as a compulsory subject")
}
}
class Teacher () : Klass() {
fun teaches () {
println("The teacher teaches all the 50 students chemistry")
}
}
fun main () {
val teach = Teacher ()
teach.students()
teach.subject()
}
- class Klass is the super or the primary class while class Teacher is the subclass or the secondary class.
Visibility Modifiers in Classes
- To make encapsulation possible you need to hide some properties and methods so that they can be used inside of a class but not outside of it. To do that you use the private visibility modifier before a function or a property you want to hide.
- Private means that a particular property or a function can only be used in that class.
- Protected means that a property can be used inside classes that are open or abstract.
- Internal means that an element will be visible throughout the same module.
💫💫Thank you for taking the time to read my article, I appreciate your interest and support.😇😇🥳🥳
Top comments (0)