Java面向对象(上)

面对对象概述

面向过程(POP)与面向对象(OOP)

面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做

面向对象:强调具有功能的对象,以类/对象为最小单位,考虑谁来做。面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法和原则,如抽象、分类、继承、聚合、多态等。

面向对象的三大特征

  1. 封装
  2. 继承
  3. 多态

面向对象的思想概述

程序员从面向过程的之性质转化成了面向对象的指挥者。

面向对象分析方法分析问题的思路和步骤:

  1. 根据问题需要,选择问题所针对的现实世界中的实体。
  2. 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
  3. 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造晨计算机能够识别和处理的数据结构。
  4. 将实例化成计算机世界中的对象,对象是计算机世界中解决问题的最终工具。

面向对象的两个要素——类和对象

对象:是实际纯在的该事物的每个个体,因而也称为实例(instance)

定义类

类(class)和对象(object,也被称为实例),其中类是对一类事物的描述,是抽象的、概念上的定义。定义类的简单语法如下:

1
2
3
4
5
[修饰符] class 类名 {
零到多个构造器定义...
零到多个成员变量...
零到多个方法...
}

设计类,其实就是设计类的成员,对与一个类定义而言,可以包含三种常见的成员:构造器、成员变量和方法,这些成员都可以定义零到多个。

创建类的对象 = 类的实例化 = 实例化类

其中修饰符可以是public、final、abstract,也可以省略。为了程序的可读性,Java类名是一个或多个有意义的单词连接而成,采用驼峰命名规则。

对于一个类的定义而言,构造器、成员变量和方法可以定义零到多个,但在类中三个成员数量都为零,就相当于建了一个空类没有太大的意义。

类中三项成员定义的顺序没有任何影响,各成员之间可以相互调用,

成员变量用于定义该类或该类的对象(实例)所包含的的状态数据,方法则用于定义该类或该类实例的行为特征或功能实现。构造器用于构造该类的对象(实例),Java语言通过关键字来调用构造器,从而返回该类的对象(实例)。

构造器是一个类创建对象的根本途径,如果一个类没有构造器,这个类通常无法创建实例。

定义成员变量的语法格式如下:

1
2
[修饰符] 类型 成员变量名 = [默认值] 
public int a = 0;
  • 修饰符:可以是public、protected、private、static、final,其中public、protected、private三个最多出现一个,可以于static、final组合修饰成员变量,public static final int a = 0;其中修饰的成员变量a被称为常量
  • 类型:包括基本数据类型和引用数据类型。
  • 成员变量名:成员变量名是一个合法的标识符即可。
  • 默认值:定义的成员变量还可以指定一个可选的默认值。

在类中成员变量一般不赋初始值,当某个类有age成员变量(属性)时,意味着该类包含setAge()和getAge()两个方法。

定义方法的语法格式如下:

1
2
3
4
5
6
7
8
9
10
11
[修饰符] 方法返回值类型 方法名 (形参列表){
//方法体
}

public void test(int a){
System.out.println("hello"+a);
}

public int test(int a){
return a;
}
  • 修饰符:可以是public、protected、private、static、final,其中public、protected、private三个最多出现一个,static、final最多可以出现一个,它们可以和static组合修饰方法。
  • 方法返回值类型:方法返回值类型可以是基本数据类型或引用数据类型,如果方法声明了方法返回值类型,在方法体内必须有一个有效的return语句。
  • 方法名:方法名命名规则和成员变量命名规则相同。
  • 形参列表:形参列表用于定义该方法可以接收的参数,可以不接受任何参数,一旦在定义方法时指定了形参列表,则调用方法时,必须传入一个对应的参数值。

在方法体中多条可执行语句间有严格的执行顺序,排在方法体前的总是先执行。

static关键字

static是一个特殊的关键字,它可以修饰方法、成员变量等。static修饰的成员表示它属于这个类本身,而不属于该类的单个实例,通常把static修饰的成员变量和方法称为类变量、类方法。static翻译为静态的,因此也把static修饰的成员变量和方法称为静态变量和静态方法,静态成员不能直接访问非静态成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test09 {

public static void main(String[] args) {
//报错,静态成员不能直接访问非静态成员
// test1();

//test2是静态方法可以直接访问
test2();

//想访问test1方法需要创建对象
Test09 t = new Test09();
t.test1();
}

public void test1() {
System.out.println("我是非静态成员");
}
public static void test2() {
System.out.println("我是静态成员");
}
}

static的真正作用就是区分成员变量、方法、内部类、初始化块,这四个成员到底属于类本身还是属于实例。在类中定义的成员,static相当于一个标志,有static修饰属于类的本身,没有static属于该类的实例。

类中属性的使用

属性(成员变量)和局部变量区别

相同点:

  1. 定义变量的格式: 数据类型 变量名 = 变量值
  2. 先声明、后使用
  3. 变量都有其对应的作用域

不同点:

  1. 在类中声明的位置不同

    属性:直接在类的一对括号中声明

    局部变量:声明在方法内、方法形参、代码块内、构造器内部的变量。

  2. 关于权限修饰符的不同

    属性:可以在声明属性时,指明其权限,使用权限修饰符

    ​ 常见的权限修饰符:private、public、protected、缺省 —>封装性

    局部变量:不可以使用权限修饰符

  3. 默认初始化的情况

    属性: 类的属性,根据其类型,都有初始化值

    ​ 整型:0

    ​ 浮点型:0.0

    ​ 字符型(char):0或(‘\u0000’)

    ​ 布尔型:false

    ​ 引用类型变量(类、数组、接口):null

    局部变量:没有初始化值

    ​ 在调用前一定要显示赋值,形参调用时再赋值

  4. 在内存中加载的位置

    属性:加载到对空间中

    局部变量:加载到栈空间

构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[修饰符] 构造器名(形参列表){
//零到多条可执行语句组成的构造器执行体
}

class Dog{
//成员变量
String name;
int age;

//构造器
public Dog() {
super();
}
public Dog(String name, int age) {
super();
this.name = name;
this.age = age;
}

//普通方法
public void eat(){
System.out.println("吃");
}
}
  • 修饰符:修饰符可以省略,也可以是public、protected、private其中之一。
  • 构造器名:构造器名必须和类名相同。
  • 形参列表:和定义方法的形参列表相同

构造器既不能定义返回值类型,如果构造器定义了返回值类型,或使用void声明构造器没有返回值,Java会将这个构造器当作方法处理,它就不再是构造器。

实际上构造器是有返回值的,当使用new关键字来调用构造器时,构造器就返回该类的实例,可以将这个实例当作构造器的返回值,因此构造器的返回值类型总是当前类,无需定义返回值类型。要注意的是:不要在构造器中使用return来返回当前类的对象,因为构造器的返回值是隐式的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Person{
//成员变量
public String name;
public int age;

/*
public Person() {
super();
}
*/
//定义方法
public void say(String content){
System.out.println(content);
}
}

上面代码中Person类中没有定义构造器,系统会为它提供一个默认的构造器,系统提供的构造器总是没有参数的。

Java类的作用:定义变量、创建对象、调用类的类方法或访问类的类变量。

类中方法的使用

方法:描述类应该具有的功能

比如:Math类:sqrt()\random()…

​ Scanner类:NextXxx()…

​ Arrays类:sort()\toString()\equals()…

  1. 方法的声明:``

对象的产生和使用

创建对象的根本途径是构造器,通过new关键字来调用某个类的构造器即可创建这个类的实例。

1
2
3
4
5
6
7
8
//使用Person定义一个Person类型的对象
Person p;
//通过new关键字调用Person类的构造器,返回一个Person实例
//将该Person实例赋值给p变量
p = new Person();

//上述代码也可转换成
Person p = new Person();

创建对象后,就可使用该对象,Java的对象作用有:访问对象的实例变量、调用对象的方法。如果访问权限允许,类中定义的方法和成员变量都可以通过类或实例调用。

static修饰的类方法和成员变量,既可以通过类来调用,也可以通过实例来调用。没有static修饰的普通方法和成员变量,只有通过实例来调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test11 {

public static void main(String[] args) {
Person p = new Person();
p.eat();
p.hight(180);
}

}

class Person{
public String name;
public int age;

public void eat() {
System.out.println("吃饭");
}

public void hight(int tall) {
System.out.println("身高为:"+tall);
}
}

大部分时候定义一个类就是为了重复创建该类的实例,同一个类的多个实例具有相同的特征,而类则是定义了多个实例的共同特征。从某个角度看,类定义的是多个实例的特征,因此类不是一个具体的存在,实例才是具体的存在。

对象、引用和指针

Person p = new Person();代码中创建了一个Person类型的实例,也被称为Person对象,这个Person对象被赋给变量p。上述代码中其实产生了两个东西:一个是变量p ,一个是Person对象。

对象内存解析

Jvm内存

与数组类型类似,类也是一个引用数据类型,在程序中Person类型的变量实际上是一个引用,它被存放在栈内存中,实际指向Person对象。真正的Person对象则存放在堆内存中。

引用对象指向实际对象

栈内存中的引用变量并未真正存储对象的成员变量,对象的成员变量数据实际存放在堆内存中。而引用变量只是指向该堆内存里的对象。实际上,Java里的引用就是C里的指针。

当一个对象被创建成功以后,这个对象将保存在堆内存中,Java程序不允许直接访问堆内存中的对象,只能通过该对象的引用操作该对象。不管对象还是数组,都只能通过引用来访问它们。

不管对象还是数组,当程序访问引用变量的成员变量或方法时,实际上是访问引用变量所引用的数组、对象的成员变量或方法。

堆内存中的对象可以有多个引用,即多个引用指向一个对象。

对象this引用

this关键字总是指向调用该方法的对象,根据this出现位置的不同有两种情况:

  1. 构造器中引用该构造器正在初始化的对象。
  2. 在方法中引用调用该方法的对象。

this关键字最大的作用就是让类中的一个方法,访问该类里另一个方法或实例变量。

大部分时候,一个方法访问该类中定义的其他方法、成员变量时加不加this前缀的效果是完全一样的。对于static修饰的方法而言,则可以使用类来直接调用该方法,如果在static修饰的方法中使用this关键字,则这个关键字就无法指向合适的对象。所以static修饰的方法不能使用this引用,Java语法规定:静态成员不能直接访问非静态成员。