面向对象学习的 三条主线:
1.Java类及类的成员:属性、方法、构造器;代码块、内部类。
2.面向对象的大特征:封装性、继承性、多态性、(抽象性)。
3.其它关键字:this、super、static、final、abstract、interface、package、import等。
一、类和对象
Java类及类的成员:属性、方法、构造器;代码块、内部类
1、面向对象中两个重要的概念:
类:对一类事物的描述,是抽象的、概念上的定义
对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)
面向对象程序设计的重点是类的设计
设计类,就是设计类的成员。
2、完成一个项目(或功能)的思路:
根据问题需要,选择问题所针对的现实世界中的实体。
从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
3、二者的关系
对象,是由类new出来的,派生出来的。
4、面向对象思想落地实现的规则
1.创建类,设计类的成员。
2.创建类的对象。
3.通过“对象.属性”或“对象.方法”调用对象的结构。
补充:几个概念的使用说明
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数 = method
创建类的对象 = 类的实例化 = 实例化类
5、对象的创建及内存解析
典型代码:
创建对象语法: 类名 对象名 = new 类名();
Person p1 = new Person(); Person p2 = new Person(); Person p3 = p1;//没有新创建一个对象,共用一个堆空间中的对象实体。
说明:如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。
内存解析:
二、类的结构:属性、方法、构造器
1、属性
语法格式: 修饰符 数据类型 属性名 = 初始化值 ;
对比:属性 vs 局部变量
相同点:
定义变量的格式:数据类型 变量名 = 变量值。
先声明,后使用。
变量都其对应的作用域 。
不同点:
1、在类中声明的位置的不同
属性:直接定义在类的一对{}内
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
2、关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符:private、public、缺省、protected —>封装性
局部变量:不可以使用权限修饰符。
3、默认初始化值的情况:
属性:类的属性,根据其类型,都默认初始化值。
整型(byte、short、int、long:0)
字符型(char:0 (或’\u0000’))
布尔型(boolean:false)
引用数据类型(类、数组、接口:null)
局部变量:没默认初始化值。
意味着,我们在调用局部变量之前,一定要显式赋值。
特别地:形参在调用时,我们赋值即可。
4、在内存中加载的位置:
属性:加载到堆空间中 (非static)
局部变量:加载到栈空间
在方法体外,类体内声明的变量称为成员变量。
在方法体内部声明的变量称为局部变量。
2、方法
2.1、方法的定义
方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中
也称为函数或过程。
将功能封装为方法的目的是,可以实现代码重用,简化代码。
Java里的方法不能独立存在,所有的方法必须定义在类里。
比如:Math类:sqrt()\random() …
Scanner类:nextXxx() …
Arrays类:sort() \ binarySearch() \ toString() \ equals() \ …
2.2、方法的重载
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数
类型不同即可。
重载的特点:
与返回值类型无关,只看参数列表,且参数列表必须不同。 (参数个数或参数类
型)。调用时, 根据方法参数列表的不同来区别。
重载示例:
//返回两个整数的和
int add(int x,int y){return x+y;}
//返回三个整数的和
int add(int x,int y,int z){return x+y+z;}
//返回两个小数的和
double add(double x,double y){return x+y;}
public class PrintStream { public static void print(int i) {……} public static void print(float f) {……} public static void print(String s) {……} public static void main(String[] args) { print(3); print(1.2f); print("hello!"); } }
2.3、可变个数的形参
JavaSE 5.0 中提供了Varargs(variable number of arguments)机制,允许直接定
义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可
变的实参。
//JDK 5.0以前: 采用数组形参来定义方法,传入多个同一类型变量 public static void test(int a ,String[] books); //JDK5.0: 采用可变个数形参来定义方法,传入多个同一类型变量 public static void test(int a ,String…books);
举例:
public void test(String[] msg){ System.out.println(“含字符串数组参数的test方法 "); } public void test1(String book){ System.out.println(“****与可变形参方法构成重载的test1方法****"); } public void test1(String ... books){ System.out.println("****形参长度可变的test1方法****"); } public static void main(String[] args){ TestOverload to = new TestOverload(); //下面两次调用将执行第二个test方法 to.test1(); to.test1("aa" , "bb"); //下面将执行第一个test方法 to.test(new String[]{"aa"}); }
2.4、方法参数的值传递机制
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
形参:方法声明时的参数。
实参: 方法调用时实际传给形参的参数值。
public class ValueTransferTest { public static void main(String[] args) { System.out.println("***********基本数据类型:****************"); int m = 10; int n = m; System.out.println("m = " + m + ", n = " + n); n = 20; System.out.println("m = " + m + ", n = " + n); System.out.println("***********引用数据类型:****************"); Order o1 = new Order(); o1.orderId = 1001; Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。 System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId); o2.orderId = 1002; System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId); } } class Order{ int orderId; }
基本数据类型:*****
m = 10, n = 10
m = 10, n = 20
引用数据类型:*****
o1.orderId = 1001,o2.orderId = 1001
o1.orderId = 1002,o2.orderId = 1002
Java的实参值如何传入方法呢?
Java里方法的参数传递方式只有一种: 值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参。
形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参。
3、构造器
语法格式:
修饰符 类名 (参数列表) {
初始化语句;
}
3.1、构造器的特征
- 它具有与类相同的名称
- 它不声明返回值类型。(与声明为void不同)
- 不能被static、 final、 synchronized、 abstract、 native修饰,不能有return语句返回值
3.2、构造器的作用:
创建对象;给对象进行初始化。
如: Order o = new Order(); Person p = new Person(“Peter”,15);
如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人” 的构造器中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们要“洗澡”了。
public class Animal { private int legs; // 构造器 public Animal() { legs = 4; } public void setLegs(int i) { legs = i; } public int getLegs() { return legs; } }
创建Animal类的实例: Animal a = new Animal(); 调用构造器, 将legs初始化为4。
根据参数不同,构造器可以分为如下两类:
隐式无参构造器(系统默认提供)
显式定义一个或多个构造器(无参、有参)
注意:
Java语言中,每个类都至少有一个构造器。
默认构造器的修饰符与所属类的修饰符一致。
一旦显式定义了构造器, 则系统不再提供默认构造器。
一个类可以创建多个重载的构造器。
父类的构造器不可被子类继承。
3.3、构造器重载
构造器一般用来创建对象的同时初始化对象。如
class Person{ String name; int age; public Person(String n , int a){ name=n; age=a;} }
构造器重载使得对象的创建更加灵活,方便创建各种不同的对象。
构造器重载举例:
public class Person{ public Person(String name, int age, Date d) {this(name,age);…} public Person(String name, int age) {…} public Person(String name, Date d) {…} public Person(){…} }
构造器重载,参数列表必须不同。
三、封装与隐藏
我们程序设计追求“高内聚,低耦合”。
高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
低耦合 : 仅对外暴露少量的方法用于使用。
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提
高系统的可扩展性、可维护性。通俗的说, 把该隐藏的隐藏起来,该暴露
的暴露出来。 这就是封装性的设计思想。
1、信息的封装和隐藏
Java中通过将数据声明为私有的(private), 再提供公共的( public)
方法:getXxx()和setXxx()实现对该属性的操作, 以实现下述目的:
隐藏一个类中不需要对外提供的实现细节;
使用者只能通过事先定制好的方法来访问数据, 可以方便地加入控制逻辑,
限制对属性的不合理操作;
便于修改, 增强代码的可维护性。
public class AnimalTest { public static void main(String[] args) { Animal a = new Animal(); a.name = "大黄"; // a.age = 1; // a.legs = 4;//The field Animal.legs is not visible a.show(); // a.legs = -4; // a.setLegs(6); a.setLegs(-6); // a.legs = -4;//The field Animal.legs is not visible a.show(); System.out.println(a.name); } } class Animal{ String name; private int age; private int legs;//腿的个数 //对属性的设置 public void setLegs(int l){ if(l >= 0 && l % 2 == 0){ legs = l; }else{ legs = 0; // 抛出一个异常(暂时没有讲) } } //对属性的获取 public int getLegs(){ return legs; } public void eat(){ System.out.println("动物进食"); } public void show(){ System.out.println("name = " + name + ",age = " + age + ",legs = " + legs); } //提供关于属性age的get和set方法 public int getAge(){ return age; } public void setAge(int a){ age = a; } }
2、四种访问权限修饰符
Java权限修饰符public、 protected、 (缺省)、 private置于类的成员定义前,用来限定对象对该类成员的访问权限。
对于class的权限修饰只可以用public和default(缺省)。
- public类可以在任意地方被访问。
- default类只可以被同一个包内部的类访问。
本系列文章参考尚硅谷课程。