初识面向对象
什么是对象?
- 对象不仅在编程领域,而且在现实生活中都是一个非常重要的概念。我们需要理解一个概念,“万物皆对象”。显示存在的客观事物都是对象。比如长城,电脑,一件衣服,一只狗,一只猫都是对象。只要是现实生活中存在的都是对象。
- 对象可以分为两部分,一种是静态的部分,比如一个人的性别,年龄,姓名等,这些称之为属性。另一种是动态的部分,比如人可以行走,吃饭,睡觉等,这些可以称之为方法。
什么是类?
类可以理解成一个抽象的笼统的概称,比如小明和小李都有各自的名字和爱好,但是他们俩都有一个共同的属性和行为—人类。类就是模子,用于确定对象将会拥有的特征(属性)和行为(方法)。
什么是面向对象?
从字面上理解,面向对象就是与对象面对面,关注对象。从计算机的角度,就是关注现实存在的事物的各方面信息,从对象的角度出发根据事物的特征进行程序的设计。
在现实生活中,我们也可以看到类和对象的概念:
- 比如电脑,电脑由cpu,硬盘,内存条,显卡等属性构成,电脑可以办公,娱乐,编写程序等动作方法,这些加起来可以称之为类,具体的某一台电脑可以称之为一个对象。
- 比如水果,有苹果,梨子,桃子等,水果这个大的概念可以看作类,具体的苹果梨子可以看作是一个个对象。
- 人有男性和女性,他们都有各自的姓名,性别,也有各自的行为,人类可以统一他们相同的属性,具体的个人可以看作是一个个对象。
- 一张建筑图纸可以造出具体的一幢房子,建筑图纸就可以看作是类,具体造出来的房子就可以看作是具体的对象
- 狗按体型可以分为小型犬,大型犬等,按功能可以分为家庭犬,工作犬狩猎犬等,具体的某只狗如哈士奇就可以看作是一个对象,狗这个分类就可以看作是一个类。
- 食物可以看作是一个类,具体有米饭,面条,粥等,这些都是对象。
- 饮料可以看作是一个类,可乐,橙汁等可以看作是一个个对象。
- 树有松树,樟树,桃树等,具体的树可以看作是对象。
- 汽车按品牌可以分为宝马,奥迪,大众等,按用途可以分为货车,轿车,客车等,具体的某一辆车可以看作对象。
- 运动可以分为有氧运动,无氧运动,跑步,游泳等可以看作是一个个对象。
根据上述所说,类和对象的关系我们可以总结如下:
- 对象是类的实例化表现
- 类是对象的类型
- 对象是特定类型的数据
类与对象的定义和使用
包的管理
为了便于类文件的管理,Java 中引入了包的概念 package,类的唯一性是要带包名的。
包的命名规范
- 英文字母小写
- 域名的倒序
```
第一层是企业的域名的反写
例如:com.dodoke
第二层是企业项目的名称
例如:com.dodoke.j96、com.dodoke.crm
第三层是企业项目模块的名称
例如:com.dodoke.j96.oop、com.dodoke.crm.base
**一个Java源文件中,只能有一个package语句,而且必须放置在Java源文件的第一行。**<br />**<br />**在不同的包中,是可以定义相同类名的类的。因为一个类的唯一性是包含包名的,比如**com.ntduduke.j96.oop.Demo1**叫做类的全名。**<br />**<br />**在实际的企业开发中,是不允许出现没有包的类。**
<a name="y8YSz"></a>
#### 包的使用
使用 import 关键字将本类要使用的其他包中的类进行引入。<br />使用ALT+/可以单个引入,也可以使用CTRL+SHIFT+O全部引入。<br />如果要引入某个包下面的所有类,可以使用通配符*,例如,引入com.ntduduke.j96.oop.*,但是要注意通配符只能出现在最后。<br />对于 java.lang 包中的类,系统会自动的默认引入,不需要使用 import。
<a name="EzHwq"></a>
### 创建类
class 类名称 { 属性 (变量) ; 行为 (方法) ; }
```
public class Cat{
//成员属性(属性指有什么)、昵称、年龄、体重;
String name;//昵称
int age;//年龄
//方法(方法指能做什么):跑步、吃东西
//成员方法
//跑步的方法
public void run(){
System.out.println("我会跑步");
}
//吃东西的方法
public void eat(){
System.out.println("我会吃鱼");
}
}
类创建完成后依靠对象来展现属性和调用方法。那对象如何来的呢,这里就要引入到一个实例化的概念。
类名称 对象名称 = new 类名称 () ;
或者
类名称 对象名称 = null ;
对象名称 = new 类名称 () ;
public class CatTest{
public static void main(String[] args) {
Cat one= new Cat();
one.eat();
one.run();
System.out.println(one.month);//有默认值
}
}
当一个实例化对象产生之后,可以按照如下的方式进行类的操作:
对象.属性:表示调用类之中的属性;
对象.方法():表示调用类之中的方法。
根据上述的例子,我们总结如下几点:
- 当几个类同属于一个包时,相互之间可以直接使用。
- 类存在动态的行为和静态的特征
- 静态的特征就是具体的属性,就是类的成员所拥有的属性
- 动态的行为就是方法,类的成员所拥有的方法
- 类的成员就是对象
- 类的属性和方法只有对象可以使用
new关键字
通过new关键字可以实现对象的实例化过程,实际上也就是对象的创建过程。
类名 对象名 = new 类名();
实例化对象的过程可以分为两部分:
- 声明对象 Cat one
- 实例化对象 new Cat();
声明对象:是在内存的”栈”空间里开辟了一块空间,取名叫one,此时里面为空(null),并且对它的属性和方法的调用是不允许的。所以因为这样我们并不能像真正的对象那样使用它
实例化对象:是在内存的堆空间里开辟了一块空间,完成了对象相关信息的初始化操作
声明对象和实例化对象是在内存的两个不同的空间去完成的,接着通过赋值符号”=”把两个空间关联起来关联,将堆空间中的内存地址存放到了栈空间中,在栈当中存储的实际上是堆当中地址的引用。
当实例化对象时,栈内存和堆内存各自都开辟了空间并联系起来,所以类的属性都存在默认值(未进行初始化时)。
new关键字的作用,实际上就是去开辟新的内存空间。
Cat one= new Cat();
Cat two= new Cat();
//引用数据类型打印出来是类全名+@+内存地址的哈希值
//如果两个对象时同一个对象,那么内存地址相同
System.out.println(one);
System.out.println(two);
//== ,比较两个引用数据类型,判断内存地址是否相同
System.out.println(one == two);
我们针对于two对象,采取同样的赋值。如果修改two对象的信息则不会对one对象造成任何的影响。
Cat one= new Cat();
Cat two= one;//将one所代表的内存地址复制给了two
此时,如果对one对象进行修改,则会影响到two对象
构造方法
构造方法也称之为构造函数,构造器,是面向对象编程中的一个重要概念。
我们经常会使用构造方法来完成对象初始化的相关设置。构造方法在调用的时候必须配合new关键字,是不能被单独调用的。
注意:构造方法与类同名且没有返回值。构造方法只能在对象实例化的时候被调用
构造器本身是一个比较特殊的方法,方法名就是类名,没有返回值(和void是有区别的),构造器是类创建对象的唯一途径。
构造器的最大用处就是创建对象
无参构造方法
前面我们在定义对象时,发现并没有创建构造方法,但是我们依然可以使用构造方法去创建对象。
Cat one = new Cat();
这是因为,当没有指定构造方法时,系统(jvm)会自动添加无参构造方法。也就是说在一个类中至少会存在一个构造方法。便于我们的程序能够正常的执行,对象能够正常的进行实例化操作。
一个类中可以有多个构造方法,当有指定构造方法、无论是有参、无参的构造方法,都不会自动添加无参的构造方法。
有参构造方法
通过构造器为成员变量定义初始化值,这也是构造器的最最最重要的用途之一
比如:
public Cat(String name, int month, double weight, String species) {
name = name;
month = month;
weight = weight;
species = species;
}
但是若按照上述方法来写的话,实际上是有问题的,此处的代码逻辑发生了错误,遵循了一种就近原则 ——赋值过程中先优先的去找同一个作用范围内的成员进行赋值操作。只有找不到的情况下才会扩大作用范围,去类里面找。通俗来讲,上面的只是将参数的值重新覆盖了一遍,并没有按照我们想要的那样去赋值。
针对于这样的问题,我们可以有两种解决方案。
第一种,修改参数名,如:
public Cat(String name1, int month1, double weight1, String species1) {
name = name1;
month = month1;
weight = weight1;
species = species1;
}
第二种,用this.属性名=参数名
public Cat(String name, int month, double weight, String species) {
this.name = name;
this.month = month;
this.weight = weight;
this.species = species;
}
构造器小结
- 在栈内存中,会存储对象名, 在没有执行构造器创建对象并赋值时,此时对象名对应的值应为null
- 通过new关键字调用类的构造器在堆内存中分配了一块对象区域;
- 通过赋值运算符 = ,将堆内存中的对象地址赋给栈内存中的变量名;
- 例如再次给对象的属性赋值: 通过栈内存中的地址定位到对象在堆内存中的地址,找到相应的成员变量,进行一个赋值操作
this关键字
Java中使用this关键字,指向调用该方法的对象。根据this所在的位置,大致分为两种情况
- 出现在构造器中:引用该构造器正在初始化的对象
- 出现在普通方法中: 正在调用该方法的对象
this用在类定义中,获取当前对象的属性,或者调用当前对象的方法。
public Cat(String name, int month, double weight, String species) {
this.name = name;//this代表对象,只有对象才能调用成员属性和方法
this.month = month;
this.weight = weight;
this.species = species;
}
说明:
- 在类定义中,可以省略this关键字去调用属性或者方法,但是在类被编译的时候,编译器还是会加上this关键字。所以我们强烈建议在类定义的时候如果要调用该类中的普通成员变量或者方法,还是要把this给加上去
- 用static修饰的方法是不能使用this关键字的
构造方法的调用
构造方法可以出现重载的情况。
public Cat() {}
public Cat(String name) {
this.name = name;
}
public Cat(String name,int age) {
this(name);
this.age = age;
}
如上我们看出可以通过this()调用重载的构造器。
说明:
- 构造方法的调用,只能在构造方法之间来完成
- 构造方法内可以使用this()来调用构造方法(有参、无参均可,只要是申明过的),且必须放在方法体内第一行。而且不允许出现两条this()语句。
- 构造方法在类内,普通方法不能调用构造方法
- 构造方法在类外进行调用时,只能配合new关键字
类中的普通方法之间可以互相调用,如
public void run(){
Cat(); //出错,普通方法不能调用构造方法
eat();//可以调用普通方法
System.out.println("aaa");
}
总结
一个Java类中可以包含的内容
public class 类名() {
//属性
访问修饰符 数据类型 属性名;
//方法
访问修饰符 返回类型 方法名(参数列表) {
}
//构造方法
访问修饰符 类名() {
}
访问修饰符 类名(参数) {
}
}