目录
面向对象编程是将现实生活中的概念通过程序进行模拟,其中有两个最重要的概念:对象,类。
所有现实世界存在的具体事物都是对象,如一个人,一台计算机,一个房间等。
对象具有属性和行为,例如,人的属性包括年龄,体重等,行为包括吃饭,走路,说话等
对象是指某个具体事物,而同一类事物有其共性,前面说到的属性和行为就是其共性。例如所有人的身高,体重等基本特征,也都具有吃,喝,玩,乐等这些共性。更为好地描述一类事物,我们对这些共性进行了归纳,就形成了类,这个过程我们称为"抽象"。
类的概念:
类是对具有相同特征或属性,具有相同行为能力的一类事物的描述或称呼
对象的概念:
对象是这一类事物带有属性值,具有具体行为的个体或实例
用一句话概括类与对象的关系
类是对象的抽象 对象是类的具体
我们对类和对象已经有了一些模糊的概念,但这和编程有什么关系呢?与以前的编程方式有什么不同呢?以前的编程方式是面向过程,每个具体功能都需要我们去进行具体的实现,而面向对象的思路则不同,我们需要完成某个功能,只需要向对象发送一个“命令”而具体怎么完成功能,是由该对象所属的类去定义的。
类的定义
面向对象编程的基本元素是类,类确定了对象的形式和行为,类是一个模板,用于创建同一类型的对象,那代码中是如何表示类呢?也就是类是如何声明的
类的声明:
在Java中定义一个类使用关键字class,一个合法的标识符和一对表示程序体的大括号,实例如下:
class <classname>{ //class关键字 classname表示类的名称,类名是一个名词,采用大小写混合的方式
//括号里包含属性和方法的声明
}
类的声明:
下面以人类为例,看看如何写一个"人"的class,代码如下
public class Person{ //声明了一个Person类
}
这就是一个完整的类的声明,当然Person类并没有定义属性和方法,它是"面目全非"的,既没有身高,性别,年龄等属性,也没有吃,喝,玩,乐等行为,当然目前也不能做任何是。确切的说,其实"类"不具备做事的功能,事情有类来定义,但是事情是由对象来做的就好像我们听到的"张三去跳舞了",但是没有人说"人类去跳舞了",这就是类和对象的区别。类是虚拟的,对象才是实实在在的,但对象是由类这个模板产生的。
那么如何给类添加对应的属性和行为。
类的属性:
下面来看看如何用变量来表示这些"属性",我们对"人类"进行完善,添加一些属性
Publicclass Person{
String name; //姓名
int age; //年龄
String sex //行为
String address; //地址
}
这样我们就已经学会了如何在class中声明属性
类的行为:
学完了属性,我们知道了如何反映物体的特性,现在想让对象来帮我们做一下具体的事情,以人类为例,想想人都能做些什么是事情呢?人都会吃饭,睡觉,行走.....显然这些是人都会做的,现在来学习如何声明这些"行为","行为"是完成某个具体的动作,我们用方法表示行为,如一下代码
Publicclass Person{
String name; //姓名
int age; //年龄
String sex //行为
String address; //地址
void eat(){ //方法:吃饭
System.out.prinltn("我会吃饭");
}
void run(){ //方法:跑步
System.out.prinltn("我会跑步");
}
}
声明"行为"其实就是在类中声明方法。现在一个带有属性和行为的具体类就被声明出来了,属性用变量来表示,行为用方法来表示
人类{
姓名; //属性
年龄; //属性
性别; //属性
地址; //属性
跑步{....} //方法
吃饭{....} //方法
}
要注意,到此为止,虽然类已经比较完善了,但自始至终并未产生一个能做事的对象来,我们只是把所有人的公共特点、行为通过类的形式归纳抽象出来。那么如何使用这个类,该如何通过这个类,产生一个具有姓名、年龄等属性,可以吃饭跑步的对象呢?
对象的创建
类的声明是对某一类事物的描述,是一种抽象概念,要想使用类就需要生成该类的对象,下面我们来学习如何创造类的对象。
使用关键字new创建对象:
创造对象可以用new关键字,语法如下:
Person p ;
p = new Person();
这句简单的代码就是使用关键字new来创建一个类的对象,对象的"名字"就叫叫做"p",是对该对象的一个引用,也就是在学习数据类型的时候提到的引入数据类型。注意new关键字的作用,new世界和三个是再分配内存空间,用于存放p这个对象
第一句代码实际上只是表示“我们要生一个 baby,名字已经起好了,叫 p”,第二句才是
真正的 baby 降生(内存分配)。那要是这个 baby 正在出生的时候起名字呢?我们通常会来
取下面这种声明方式:
Person p = new Person();
与我们前面学习的基本变量声明类似,只不过是声明的变量类型是自定义的类型而
西且需要采取 new 关键字,对比一下
Person p = new Person();
int i = 0;
通过对象访问属性和行为:
创建对象后,该如何使用它?
Publicclass Person{
String name; //姓名
int age; //年龄
String sex //行为
String address; //地址
void eat(){ //方法:吃饭
System.out.prinltn("我会吃饭");
}
void run(){ //方法:跑步
System.out.prinltn("我会跑步");
}
/*main方法*/
public static void main(String[]args){
//定义对象Person对象p
Person p ;
p = new Person();
//给p这个人起名字,定义年龄等属性值
p.name = "张三";
p.age = 18;
p.sex ="女";
p.address = "武汉徐东";
//调用对象p的属性及方法
System.out.println(p.name+"说:");
System.out.println("我叫"+p.name);
System.out.println("性别: " +p.sex);
System.out.println("我今年"+p.age+"岁");
System.out.println("我住在"+ p.address);
p.eat(); //调用方法
p.run();
}
}
运行的结果如下图:
其实上面的属性和方法是在main()方法内才被调用的,我们可以更灵活一点,从而完成更强大的功能,比如以下代码
public class Person {
String name; // 姓名
int age; // 年龄
String sex; // 行为
String address; // 地址
void eat() { // 方法:吃饭
System.out.println("我会吃饭");
}
void run() { // 方法:跑步
System.out.println("我会跑步");
}
// 自我介绍
void introduce() {
System.out.println(name + "说:");
System.out.println("我叫" + name);
System.out.println("性别: " + sex);
System.out.println("我今年" + age + "岁");
if (age <= 0) {
address = "北京,有事你等我";
} else if (age < 100) {
address = "武汉,有事你call我";
} else {
address = "上海,有事你来找我";
}
System.out.println("我在" + address);
eat();
run();
}
/* main方法 */
public static void main(String[] args) {
// 定义Person对象p
Person p = new Person();
// 给p这个人起个名字,定义年龄等属性值
p.name = "张三";
p.age = 18;
p.sex = "女";
// 让p做自我介绍
p.introduce();
}
}
在introduce()方法中,使用了name、address等属性,注意在该方法内是直接使用,因为定义时并不存在恩和对象,所以不能写为如p.name、p.eat()等。而在main()方法运行时,我们创建了p对象,并给姓名、年龄、性别三个属性赋了值,调用introduce方法p.introduce(), introduce()方法内的姓名、年龄等属性会自动指定为p对象的对应属性。
属性的默认值:
在定义类的属性后,在使用过程中,如果没有给这些属性赋值,JVM系统将自动为这些属性赋默认值。例如:
public class DefaultValue {
int i;
float f;
double d;
char c;
boolean b;
String s;
/*输出这些属性的值*/
void test(){
System.out.println("i = "+i);
System.out.println("f = "+f);
System.out.println("d = "+d);
System.out.println("c = "+c);
System.out.println("b = "+b);
System.out.println("s = "+s);
}
public static void main(String[] args) {
/*创建对象*/
DefaultValue d = new DefaultValue();
/*调用方法*/
d.test();
}
}
运行程序,输出结果如图:
可以看到,数值类型的初始值为 0,对于 char 类型,其值为“\u0000”,显示为空字符,boolean 类型的初始值为 false,而引用类型(如 String)的初始值为 null。通常情况下,为这些对于基本数据类型成员变量,JVM 会根据相应的数据类型初始化默认值,如 int 数据类型的默认值是0,即使不再初始化它们也能正常使用,只是初始数值可能不是我们所期望的数值而已。但引用数据类型(如 String)的初始默认值是 null,当试图操作该引用数据类型所指向的对象时,会造成运行时错误。
在编程过程中,虽然说每一个类的属性均有默认值,但是为了避免错误,我们应当在使用这些属性之前,对每个属性进行手工赋值。
构造方法
Person p;
p = new Person();
其中,“Perwon p:”指的是声明一个类型为“Person”的对象 p,注意仅仅是声明,并未真正让这个p诞生,第二句话才是生产p的过程,new 关键字用于分配内存空间来安置p对象。但是,new 后面的“Personl)”是什么?我们可以知道它是一个方法,但它是一个什么样的方法呢?而且,观察程序,我们发现并未定义过这么一个方法,且奇怪的是,方法名和类名是相同的,那它是从何而来的?
无参数的构造方法
对于一个类,如果我们不自定义构造方法,那么程序会自动构建无参数构造方法
public class Dog{
String name; //属性
void shout() { //方法
System.out.println(name + ":汪汪....");
}
public static void main(String[] args) {
DogTest dog = new DogTest();
dog.name = "旺财";
dog.shout();
}
}
程序中并未定义 Dog()方法,但在 main()方法内依然可以调用,从而创建 Dog 对象。
这其中的原因就是编译器完成了默认构造方法的创建,即:
public class Dog{
String name; //属性
Dog(){} //默认构造方法,有系统自动添加
void shout() { //方法
System.out.println(name + ":汪汪....");
}
public static void main(String[] args) {
DogTest dog = new DogTest();
dog.name = "旺财";
dog.shout();
}
}
可以看到,构造方法的名称与类名一样,而且构造方法没有返回值;另外,当类中已经创建了构造方法时,编译器就不再为类自动创建构造方法。编译器自动创建的构造方法为空方法,当然,我们自定义构造方法时,可以更灵活地运用。例如,我们经常使用构造方法来完成属性的初始化,以避免在生成对象后出现大量的赋值语句。
如下列代码:
public class Dog {
String name;
Dog() {
System.out.println("构造方法被调用");
name = "旺财";
}
void shout() {
System.out.println(name + ":汪汪....");
}
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "旺财";
dog.shout();
}
}
运行程序,结果如下图:
本程序使用自定义无参数构造方法来完成属性的初始化,使得一只狗一出生就有了"旺财"的名字,另外,仔细观察结果发现,构造方法的确实在创建对象时被调用。注意构造方法和普通方法的区别
那么有没有办法能够实现在创建对象的同时,自由指定属性的值呢?下面就要用到带参数的构造方法。
带参数的构造方法
无参数的构造方法,既然叫方法,那么就代表构造方法可以和一般方法那样带参数,带参数的构造方法可以更灵活的给我们的属性赋值。还用Dog来表示有参构造方法如下
public class Dog {
String name;
//构造方法,接收一个字符串参数
Dog(String dogName) {
System.out.println("构造方法被调用");
name = dogName; //把参数值给name属性
}
void shout() {
System.out.println(name + ":汪汪....");
}
public static void main(String[] args) {
// 调用带参数的构造方法生成小狗旺财
Dog dog = new Dog("旺财");
dog.shout();
// 调用带参数的构造方法生成小狗来福
Dog dog1 = new Dog("来福");
dog1.shout();
}
运行结果如下图:
在程序中,我们定义了一个带字符串参数的构造方法,构造方法内把字符串参数的值赋给类属性name,mian()方法中,创建了两个对象,分别传递不同的参数值,由此得到两个不同名的小狗对象,显然,这比无参数构造方法更加灵活
对于上例,在类中已经声明了一个带参数的构造方法下,编译器是不会自动生成无参数的默认构造方法。
那么也就是 说构造方法用于初始化成员属性,通过new调用构造方法来初始化对象。当没有创建无参构造方法时,系统会自动创建一个无参的构造方法;当创建了构造方法,系统就不再帮我们创建构造方法了,此时调用构造方法,就需要使用自己创建的构造方法。