Day07
面向对象
何谓面向对象?
>面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
>面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
面向对象的三大特征:
>封装:封装就是把对象的属性(状态)和方法(行为)结合在一起,并尽可能隐蔽对象的内部细节,成为一个不可分割的独立单位(即对象),对外形成一个边界,只保留有限的对外接口使之与外部发生联系。
>继承:继承是软件重用的一种形式,它通过重用现有类的属性和方法,并增加新功能或修改现有功能来构建新的类。
>多态:多态是指在父类中定义的属性或方法被子类继承之后,可以具有不同的表现行为。这使得同一个属性或方法在父类及其各个子类中具有不同的语义。
Java语言的基本元素:类和对象
类(Class)和对象(Object)是面向对象的核心概念。
-
类是对一类事物的描述,是抽象的、概念上的定义
-
对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
”万事万物皆对象“
面向对象的思想概述:
可以理解为:类 = 抽象概念的人;对象 = 实实在在的人
面向对象程序设计重点是类的设计。
类的设计,其实就是类的成员的设计。
类的成员有:
>属性:对应类中的成员变量
>行为:对应类中的成员方法
类的语法格式:
修饰符 class 类名 {
属性声明;
方法声明;
}
说明:修饰符public:类可以被任意访问类的正文要用{ }括起来
public class Person {//属性String name;int age;int sex;//行为(方法)public void study(){System.out.println("studying");}
}
声明一个类
定义一个长方形(Rectangle)类,有长、宽属性,对每个属性都提供相应的get/set方法 。
public class Rectangle {/* 长方形宽度 */private double width;/* 长方形高度 */private double length;/* 成员变量对应的方法 */public double getWidth() {return width;}public void setWidth(double width) {this.width = width;}public double getLength() {return length;}public void setLength(double length) {this.length = length;}
}
对象的创建:
当创建完一个类时,就创建了一种新的数据类型。可以使用这种类型来声明该种类型的对象。
//第一种
Rectangle rectangle = new Rectangle();
//第二种
Rectangle rectangle;
rectangle = new Rectangle();
构造方法
类的构造方法
-
构造方法是一种特殊的方法,在对象被创建时用来初始化对象;
-
它具有和它所在的类完全一样的名字;
-
构造方法和类的方法类似,只不过构造方法没有返回类型;
-
构造方法的任务是初始化一个对象的内部状态。
[] <class_name> ([<argu_list>]){
语句;
}
类的构造方法实例
在Rectangle 类的基础上,基于width和length两属性来创建构造方法,代码如下所示:
public class Rectangle {private double width;private double length;/* 利用width和length创建构造方法 */public Rectangle (double width, double length) {this.width = width;this.length = length;}//省略……
}
this关键字代表当前所在类的对象,即本类对象,用于解决变量的命名冲突和不确定性问题;在没有同名的情况下,可以直接使用属性的名字。
对象的初始化
Rectangle rectangle = new Rectangle(3,5);
注意:如果在类中没有定义任何的构造方法,则编译器将会自动加上一个无参构造方法 ;一旦创建了自己的构造方法,缺省的构造方法将不复存在,如果需要则手动添加无参构造方法。
类的方法
方法是类行为的体现,其他对象可以根据类的方法对类进行访问。类的方法包括方法的说明和方法的实现两部分。
[access] [modifiers] <return_type> methodName ([<argu_list>]) {
//省略…
}
注意:方法的返回类型是该方法运行后返回值的数据类型;如果方法没有返回值,则方法的返回类型为void。
使用对象
当分配完一个对象后,可以使用点操作符“.”来实现对属性和方法的访问:
? 对象名.属性; //访问对象的属性
? 对象名.方法名(); //访问对象的方法
public class Rectangle {
//……省略变量定义及构造方法定义
//……省略 get和set方法/* 输出长方形的长宽信息 */public void output() {System.out.println("长方形的长为:" + length);System.out.println("长方形的宽为:" + width);}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入长方形的长:");double length = scanner.nextDouble();System.out.println("请输入长方形的宽:");double width = scanner.nextDouble();// 利用构造方法创建一个Rectangle类型的对象Rectangle rectangle = new Rectangle(width, length);//调用output方法rectangle.output();}
}
传递参数
值传递
值传递(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形试参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。
public static void main(String[] args) {int num = 5;System.out.println("调用change方法前 : " + num);//创建一个CallByValue类型的对象CallByValue callByValue = new CallByValue();callByValue.change(num);System.out.println("调用change方法后 : " + num);
}
/*定义change方法*/
public void change(int num) {num += 5;System.out.println("在change中 num的值为 : " + num);
}
引用传递
引用传递(形式参数炎型是引用数强炎型参数):也称为传地址,方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。
class CallByRef {int a, b;CallByRef(int i, int j) {a = i;b = j;}void change(CallByRef obj) {obj.a = 50;obj.b = 40;System.out.println("在change方法中 obj.a=" + obj.a + ",obj.b=" + obj.b);}
}
public class Test {public static void main(String[] args) {CallByRef obj = new CallByRef(15, 20);System.out.println("调用change方法前 obj.a=" + obj.a + ",obj.b=" + obj.b);obj.change(obj);System.out.println("调用change方法后 obj.a=" + obj.a + ",obj.b=" + obj.b);}
}
方法重载
重载
-
在Java程序中,如果同一个类中存在两个方法同名,方法的签名(参数个数、参数类型、类型排列次序)上也一样,将无法编译通过。
-
但在Java中多个方法重名是允许的,只要保证方法签名不同即可,这种特性称为方法重载(overload)。
方法重载需遵循如下两条规则:
- 方法名相同
- 参数列表(个数、类型、顺序)不同
注意:返回值不影响方法重载;构造方法也可以重载 。
包
Java允许使用包将多个类组织在一起。借助于包可以方便的组织管理类,并将自定义的类与其它的类库分开管理。Java就是使用包来管理类库的 。
使用包维护类库比较简单,只要保证在同一个包下不存在同名的类即创建一个包也比较简单:只要将package命令作为一个Java源文件的第一句就可以,该文件中定义的任何类将属于指定的包。示例代码如下:
package mypackage;
public class Rectangle{//省略...
}
包中类的访问
一个类可以访问其所在包的所有类。访问其他包的类有如下两种方式访问 :
- 使用import语句导入要访问的类 ,如:
import java.util.*;
import mypackage.school.Student ;
- 使用的类名前直接添加完整的包名 ,如:
java.util.Date now = new java.util.Date();
mypackage.school.Student tom = new mypackage.school.Student();
注意:* 指明导入当前包的所有类,不能使用类似于java. * 的语句来导入以java为前缀的所有包的所有类。
封装
-
Java中为了将数据有效的保护起来,提供了访问修饰符用来声明、控制属性、方法乃至类本身的访问,以实现隐藏一个类的实现细节,防止对封装数据未经授权的访问,此种形式称为“封装”。
-
引入封装,使用者只能通过事先定制好的方法来访问数据,可以方便的加入控制逻辑,限制对属性的不合理操作,有利于保证数据的完整性。
-
实现封装的关键是不让外界直接与对象属性交互,而是要通过指定的方法操作对象的属性,如下图所示:
访问修饰符
Java中定义了private(私有的)、protected(受保护的)和public(公共的)的访问修饰符,同时也定义了一个缺省的访问级别,用于声明类、属性、方法的访问权限。明确访问修饰符的限制是用好“封装”的关键 :
-
使用public访问修饰符,类的成员可被同一包或不同包中的所有类访问,也就是说,public访问修饰符可以使类的特性公用于任何类;
-
使用protected访问修饰符允许类本身、同一包中的所有类和不同包中的子类访问;
-
如果一个类或类的成员前没有任何访问修饰符时,它们获得缺省的访问权限,缺省的可以被同一包中的其他类访问;
-
private访问修饰符是限制性最大的一种访问修饰符,被声明为private的成员只能被此类中的其他成员访问,不能在类外看到。
Java中访问控制表
访问控制 | private成员 | 缺省成员 | protected成员 | public成员 |
---|---|---|---|---|
同一类中成员 | √ | √ | √ | √ |
同一包中其他类 | × | √ | √ | √ |
不同包中子类 | × | × | √ | √ |
不同包中非子类 | × | × | × | √ |
静态变量和方法
-
在Java中,可以将一些成员限制为“类相关”的,而前面介绍的成员是“实例相关”的。
-
“实例相关”的成员描述的是单个实例的状态和方法,其使用必须要通过类的实例来完成;
-
“类相关”是在类的成员前面加上“static”关键字,从而直接通过类名就可以访问 。
注意: 类的静态变量和静态方法,在内存中只有一份,供该类的所有对象共用。
public class InstanceCounter {// 用于统计创建对象的个数public static int count = 0;public InstanceCounter() {count++;}// 用于输出count的个数public static void printCount() {System.out.println("创建的实例的个数为:" + count);}public static void main(String[] args) {for (int i = 0; i < 100; i++) {InstanceCounter counter = new InstanceCounter();}InstanceCounter.printCount();}
}
ic int count = 0;
public InstanceCounter() {
count++;
}
// 用于输出count的个数
public static void printCount() {
System.out.println(“创建的实例的个数为:” + count);
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
InstanceCounter counter = new InstanceCounter();
}
InstanceCounter.printCount();
}
}