在之前文章中已经入门简单的语法,那么接下来将讲到Java中很重要的概念——面向对象。
在Java的Wikipedia中多范式(Paradigm)的条目中是这样解释的:
generic, object-oriented (class-based), functional, imperative, reflective, concurrent
通用、面向对象(基于类)、函数式、命令式、反射式、并发
介绍
类是一种创建对象的图纸,对象是根据类所创建的实例。
可以在类中定义好属性(描述其的变量)和方法(可以执行的操作)。而根据类来创建的对象,也就具有了这些属性和可使用的方法。如果要创建多个同类对象,只需要根据同一类来创建这多个对象即可,这样大大方便了代码的复用与维护。
面向对象(OOP)可以看作为是一种编程思想,指的是利用对象之间的交互去实现功能。
这样以面向对象的形式来组织代码,就可以做到比如引入外部的类,直接使用方法和属性,而且无需知道和细究方法内部的具体实现,只需要知道方法能做到的功能即可。
对一个对象的重新认识的一个过程就是对对象进行抽象。
类的定义
public class Demo {
public int number;
public void out(){
System.out.println("OUT");
}
}
如上,一个类的定义包含:
- 类的名字,一般我们使用大驼峰命名法(如
ClassName
),名字中每个英文都是大写。 - 成员变量
- 成员方法
一般建议,一个文件中定义一个类。 且public修饰的类名必须要和文件名相同,而且这样的类名最好通过IDE的内置工具修改。
你可能会感觉到这和C语言的结构体很像,但是与之不同的是,Java的类是面向对象的,且包含了成员变量和成员方法,支持访问控制修饰符(public/private等),并且还有继承、多态等多种机制。这些会在后续展开。
类的实例化=对象
用类类型创建对象的过程,称为类的实例化。实例化的代码:
public class Test {
public static void main(String[] args) {
Demo obj = new Demo();
obj.out();
}
}
这样如第三行所示的格式,就是一个创建对象的语句。(关键字是new
, 所以常有人说“new一个对象”)
而创建好的名为obj的对象就是根据名为Demo的类创建的。之后我访问了Demo类中的成员方法(见第四行),访问或修改类中的成员一般使用点号( .
),这样就成功输出了“OUT”
这样从内存空间存储的角度上,类这个“图纸”其实并不会占用程序运行时候用的堆内存,只是作为一种设计蓝图,一种元数据被存储在方法区,而根据类创建出对象才是真正会开辟堆内存空间的,所以这样也就更好地理解了为什么创建对象能被称为“实例化”。
this引用
在成员方法内,当出现方法中定义的形参和成员变量相同的时候,就需要用this+点号( this.
)来表示指明是这个对象的成员变量。
类似的,前面说到可以一个类可以创建多个对象,那么试想在这个类中有负责传入参数的成员方法,程序如何知道传给哪个对象相应的数据?同样也是借助了 this
对当前对象的引用。
回到前面,讲讲如何对这个对象内的成员变量进行赋值。
如果只是类内对成员变量指定初始值的话直接就是一条 public int yes = 1;
即可,但是不可以拆开来两条去写,如public int yes; yes = 1;
。这是因为对于类内只能有“成员的声明”和“初始化块”,而前条语句会被判为初始化,而后者会被认为是普通语句不可使用。
如果对于对象,不同的对象希望有不同的变量值的话,则需要写修改器,这也是种成员方法。而且对于IDEA很简单,可以直接借助内置工具生成。在类的文件内右键选择 Generate… (ALT+Insert快捷键) -> 选择 Setter, 然后在弹出的窗口中选中需要使用的修改器传入值的变量。则编辑器会直接生成如下的的代码:
public void setNumber(int number) {
this.number = number;
}
你会发现,在第二行好像自带了一个 this
,没错,就是在这里做到了让程序知道值应该传递给哪个对象。只要哪个对象调用了这个方法,那么这个 this
就是代指哪个对象。只能引用当前对象,不能再引用其他对象。而且有的时候编译器会在成员方法会被执行的时候将其自动传递。
看一个自动传递的例子,还有种方法叫做访问器,这也是种成员方法。还是右键,Generate… (ALT+Insert快捷键) -> 选择 Getter,然后在弹出的窗口选择需要输出的变量。就会生成一个我们很熟悉的用于打印变量的方法:
public void numOut(){
System.out.println(number);
}
// 一般直接生成的是上面这样的
public void numOut(){
System.out.println(this.number);
}
其实简单改改自动生成的方法如第二段所示的,会发现结果也是一样。而这种情况即使不写,编译器也会自动加上 this
。
构造方法
也成为构造器,也是一个特殊的成员方法。名字必须与类名相同,在创建对象的时候由编译器自动调用,并且在整个对象的生命周期内只使用一次。
// 文件Student.java中
public class Student {
public String name;
public int age;
public String gender;
// 构造方法
public Student(String name, int age, String gender) {
this.name=name;
this.age=age;
this.gender=gender;
}
public Student(){
this.name="nameless";
this.age=0;
this.gender="boy";
}
}
需要注意的几点是:无需设置返回值也不能设置,可以重载(即同一方法可以按照使用场景设置不同的参数,如上无参数的构造方法,可以作为指定成员变量的默认值的一种方式)
如果开发者没有显式定义(如上直接在类中写出构造方法即为显式定义),则编译器会默认生成一个不带参数的构造方法。如果有则不再额外生成。
如果只是无参来指定默认值的话,上述无参的构造方法还可以用this简化为:
public class Student {
public String name;
public int age;
public String gender;
// 构造方法
public Student(){
this("nameless",0,"boy");
}
public Student(String name, int age, String gender) {
this.name=name;
this.age=age;
this.gender=gender;
}
}
注意,使用this()
调用其他构造方法时,必须将该调用语句放在构造方法的第一行
绝大多数情况下使用public
来修饰,特殊场景下会被private
修饰(单例)
对象打印
public class Main {
public static void main(String[] args) {
Student stu = new Student();
System.out.println(stu);
}
}
用上面的代码直接打印会输出 Student@3b07d329
这样的“类名@hash值”的格式。
但是如果想要打印对象中的成员变量,可以使用类中重写的 toString
方法。因为在上面的例子中,对于对象是直接进行了“sout”打印,实际上在类中是在调用一个默认的 toString
成员方法。
IDEA也可以生成一个简单的重写方法,右键,Generate… (ALT+Insert快捷键) -> 选择 toString -> 选择要打印的成员变量即可。
public class Student {
public String name;
public int age;
public String gender;
public Student(){
this("nameless",0,"boy");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
如果希望自己写 toString
,记得加上 @Override
注解确保正确重写。
之后会继续讲包、封装、还有继承、多态等,虽然在本文有部分是提到但暂不细讲,循序渐进。
评论 (0)