第3单元 面向对象(上)
面向对象基本概念: 封装、继承、多态、抽象
类、对象、实例
变量(属性)、方法(行为)
3.1 面向对象思想
1、编程(程序)语言两种思想:面向过程,面向对象
(1)面向过程:分析解决问题所需的步骤,用方法(函数)逐一实现,通过调用方法(函数)解决问题。比如:C语言,Fortran语言
(2)面向对象:将构成问题的事物,按一定的规则划分为多个对象,通过调用对象来解决问题。
说明:对象
(1)对象映射现实中的事物
(2)对象由两部分组成:变量(属性)、方法(行为)
变量(属性):描述对象的属性
+ 描述对象间的关系
方法(行为):描述对象的行为
(3)一个Java程序,包含多个对象,通过对象间的相互配合实现程序的功能。
2、面向对象三大特点: 封装性、继承性、多态性
(1)封装性:
定义:将对象的属性(变量)和行为(方法)绑定在一起,封装在对象内部
作用:信息隐藏和权限设置
(2)继承性:
定义:描述类与类的关系。通过继承,可以继续原有类的属性和行为,并能对原有类进行扩展。
例子: 普通汽车类:普通汽车属性、普通汽车功能
|
V
轿车汽车类: 普通汽车属性、普通汽车功能(继承),轿车汽车属性、轿车汽车功能(扩展)
作用:增强代码复用、扩展性,提高代码开发效率
(3)多态性:
定义:同一个属性或方法,具有不同的表现形式的能力。类型的属性或方法被其他类继承后,具有不同的数据类型或不同的行为(继承、子类重写)
例子: Cut : 理发师:剪发; 演员:停止表演
作用:实现同一属性或方法,不同的表现形式,增强代码扩展性
3.2 类与对象
面向对象思想核心:类和对象: (属性+行为)
类:类是对象的模板,描述所有对象共同的特征和行为
对象:对象是类的具体实例
说明:对象根据类创建,类可以有多个不同对象
例子: 现实生活中,学生可以是一个类
类: 学生类
对象:张三、李四、王五
属性(变量):学号,性别、年龄、身高、体重和家庭住址等
行为:吃饭、睡觉、学习、运动和打游戏等
3.2.1 类的定义
面向对象核心是对象,创建对象的前提,需要定义一个类。)
1、类:定义成员变量和成员方法
成员变量:描述对象共同的属性、特征 (多为名词,后面无成对括号)
成员方法:描述对象共同的行为 (多为动词或动宾结构,后面有成对括号)
说明:类,第2个引用数据类型
2、类的定义语法:
[修饰符] class 类名{ //[]:标识该内容可缺省
成员变量;
成员方法;
}
例子:定义一个学生类
class Student { //Student类名
String name; //成员变量:name,age,sex
int age;
String sex;
void read() { //成员方法:read()
System.out.println("大家好,我是" + name); //在成员方法read()中,直接访问成员变量name
}
}
3、成员变量与局部变量
(1)成员变量:在类中定义的变量
(2)局部变量:在方法中定义的变量
在类中,允许成员变量与局部变量同名。此时,在方法中通过变量访问的是局部变量,而非成员变量。
例子:
class Student {
int age=30; //成员变量age
void read() { //成员方法:read()
int age=50; //局部变量 age
System.out.println("大家好,我" + age+"岁了,我在看书!"); //在成员方法read()中,访问局部变量age, 输出50
}
}
3.2.2 对象的创建与使用
若要使用类,必须创建对象。
1、对象的创建
对象创建:声明对象+实例化对象(对象是引用数据类型,使用new关键字创建类的实例对象)
方法一:声明和实例化分开:
(1)声明对象语法
类名 对象名称; //声明一个对象,且该对象没有没有任何引用,即不对其进行实例化
(2)实例化对象
对象名称=new 类名(); //new关键创建类的实例对象
方法二:直接创建对象:声明和实例化同时(推荐):
类名 对象名称=new 类名();
说明:
(1)赋值号“=”左边声明一个对象(用对象变量名代替)
(2)赋值号“=”右边实例化对象
(3)赋值号“=”作用:将右边实例化对象,在内存中的首地址赋值给对象变量名
(对象变量名保存在栈内存中,对象成员变量保存在堆内存中)
例子1:声明、实例化
方法一 方法二
Student stu=null;
stu=new Student(); <=> Student stu=new Student();
例子:Student类声明,Student对象创建例子
class Student { //Student类声明
String name;
void read() {
int age=50;
System.out.println("大家好,我是" +name+",我在看书!");
}
}
public class Test{ //Student类的对象创建
public static void main(String[] args){
Student stu=new Student();
}
}
2、对象的使用
创建对象后,通过对象变量名和“.”运算符,可以使用对象访问类中的成员变量或成员方法。(“.”:读作调用)
对象的使用语法:
对象名称.属性名
对象名称.方法名
例子3-1 对象的使用
class Student {
String name; // 声明姓名属性
void read() {
System.out.println("大家好,我是" + name);
}
}
class Example01 {
public static void main(String[] args) {
Student stu1 = new Student(); // 创建第一个Student对象
Student stu2 = new Student(); // 创建第二个Student对象
stu1.name = "小明"; // 为stu1对象的name属性赋值
stu1.read(); // 调用对象的方法
stu2.name = "小华";
stu2.read();
}
}
大家好,我是小明
大家好,我是小华
说明:
1、创建两个Student对象,stu1,stu2:两个对象是完全独立的个体,各自拥有类的成员变量和方法
2、对某个对象的属性赋值,不影响其他对象的相应的属性值。
3.2.3 对象的引用传递
类属于引用数据类型:对象变量名保存的是对象在内存的首地址。同一个对象,可以被不同的对象变量引用。
例子3-2:对象的引用传递
class Student {
String name; // 声明姓名属性
int age; // 声明年龄属性
void read() {
System.out.println("大家好,我是"+name+",年龄"+age);
}
}
class Example02 {
public static void main(String[] args) {
Student stu1 = new Student (); //声明stu1对象并实例化
Student stu2 = null; //声明stu2对象,但不对其进行实例化
stu2 = stu1; // stu1给stu2分配空间使用权
stu1.name = "小明"; // 为stu1对象的name属性赋值
stu1.age = 20;
stu2.age = 50;
stu1.read(); // 调用对象的方法
stu2.read();
}
}
大家好,我是小明,年龄50
大家好,我是小明,年龄50
说明:
1、stu2=stu1:将stu1变量保存的对象的首地址,赋值给stu2变量。此时变量stu1,变量stu2,引用同一个实例化对象
3.2.4 访问控制
1、类、成员变量和成员方法,有不同的访问控制权限
2、Java提供了4种访问控制权限:
private------->default------->protected------->public
访问控制权限级别: 低------->高
(1)private:私有的。私有的成员(成员变量和成员方法),只能在本类中访问。
(2)default:默认的(缺省。成员没有写访问权限,默认是default):默认的成员,能被本类或本包其他类访问(本包),不能被其他包中的类访问。
(3)protected:受保护的。受保护的成员,只能被本包及不同包的子类访问。
(4)public:公有的。公有的成员,被所有类访问。
例子:
public class Test{
public int aa;
protected boolean bb;
void cc(){ //(默认的)cc方法
System.out.println("包访问权限");
}
private class InnerClass{ //(私有的)内部类
}
}
编译器报错。。。。
注:
1、只有成员变量有访问控制权限,局部变量没有访问控制权限,局部变量只能在其所在的方法内有效,不可能被其他类访问。
2、Java的源文件定义的所有类都没有public修饰,则该源文件名可以是合法文件名。
如果一个源文件中定义了一个public修饰的类,则该源文件名必须与public修饰的类名相同。
3.3 封装性
3.3.1 为什么要封装
原因: 细节隐藏,访问权限控制。
细节隐藏:方法的实现细节包装并隐藏起来
访问权限控制:对类种的成员(变量)和数据进行权限设置,防止外部类随意访问。
例子3-3: Example03
3.3.2 如何实现封装
定义:将对象的状态信息(成员变量和数据)隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类提供的方法实现对内部信息的操作访问。
实现:定义类的时候:私有成员变量,对外提供公有成员方法,来设置和获取私有属性值。
(具体化:私有属性,只能被本类访问;外部类想访问私有属性,只能通过公有方法设置和获取属性值。 设置方法: setter(); 获取方法:getter())
例子3-4: Example04
class Student{
private String name; // 声明姓名属性 属性私有
private int age; // 声明年龄属性
public String getName() { // getName(): 公有方法,获取私有属性值
return name;
}
public void setName(String name) { // setName(): 公有方法,设置私有属性值
this.name = name; // this.name:成员变量; name:局部变量
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<=0){
System.out.println("您输入的年龄有误!");
} else {
this.age = age;
}
}
public void read() {
System.out.println("大家好,我是"+name+",年龄"+age);
}
}
public class Example04 {
public static void main(String[] args) {
Student stu = new Student(); // 创建学生对象 (引用数据类型,创建对象后,会自动赋初值)
stu.setName("张三"); // 为对象的name属性赋值
stu.setAge(-18); // 为对象的age属性赋值
stu.read(); // 调用对象的方法
}
}
大家好,我是张三,年龄0 //年龄0: 未对其赋值,为何有值? (引用数据类型,创建对象后,若没有主动赋值,系统会自动赋初值)
说明:私有成员变量,对外部类提供公有成员方法来设置和获取私有属性值。
3.4 构造方法
问题:创建对象后,为对象属性赋值方法: 1、直接调用对象属性名,通过赋值语句: 对象名.属性名=属性值;
2、私有属性,公有方法(setter(),get()方法):
3、构造方法:实例化对象的同时,给对象属性赋值
定义:构造方法(又称构造器):类的特殊成员方法,在类实例化对象时自动调用,为对象的属性赋值。
3.4.1 定义构造方法
构造方法,注意点:
(1)构造方法名必须与类名一致。
(2)构造方法名称前不能有任何返回值类型的声明。
(3)不能在构造方法中使用return返回一个值,但是可以单独写return语句作为方法的结束。
分类:无参构造方法,有参构造方法
例子3-5: (无参)构造方法
class Student{
public Student() { //定义(无参)构造方法
System.out.println("调用了无参构造方法");
}
}
public class Example05 {
public static void main(String[] args) {
System.out.println("声明对象...");
Student stu = null; //声明对象
System.out.println("实例化对象...");
stu = new Student(); //实例化对象,实例化对象时,自动调用构造方法
}
}
声明对象...
实例化对象...
调用了无参构造方法
例子3-6: (有参)构造方法
class Student{
private String name;
private int age;
public Student(String n, int a) { //定义(有参)构造方法
name = n;
age = a;
}
public void read(){
System.out.println("我是:"+name+",年龄:"+age);
}
}
public class Example06 {
public static void main(String[] args) {
Student stu = new Student("张三",18); // 实例化Student对象
stu.read();
}
}
我是:张三,年龄:18
3.4.2 构造方法重载
方法重载:方法名相同,参数不同(类型或个数不同:3种情况)
构造方法,也可以重载。创建对象时,系统自动调用不同构造方法,为不同属性赋值。
例子3-7: 构造方法重载
class Student{
private String name;
private int age;
public Student() { //无参构造方法
}
public Student(String n) { //有参构造方法:1个参数
name = n;
}
public Student(String n, int a) { //有参构造方法:2个参数
name = n;
age = a;
}
public void read(){
System.out.println("我是:"+name+",年龄:"+age);
}
}
public class Example07 {
public static void main(String[] args) {
Student stu1 = new Student("张三");
Student stu2 = new Student("张三",18); // 实例化Student对象
stu1.read();
stu2.read();
}
}
我是:张三,年龄:0
我是:张三,年龄:18
注意:
(1)类中没有定义构造方法,系统自动创建一个无参且无函数体的默认构造方法
class Student{ class Student{
} <=> public Student(){
}
}
使用new Student()实例化对象时,系统自动调用默认构造方法
(2)当自定义构造方法后,系统不再提供默认的构造方法
(建议:自定义构造法方法后,再定义个无参的默认构造方法)
class Student{
int age;
public Student(int n){
age=n;
}
}
publc class Example08{
public static void main(String[] args) {
Student stu1 = new Student(); //编译器报错,有自定义构造方法,系统不再提供默认构造方法
}
}
编译器报错。。。。
(3)构造方法通常使用public修饰
3.5 this关键字
目的:成员变量与局部变量可能重名,使用this关键字分辨成员变量与局部变量。
作用:
(1)使用this关键字调用本类中的属性(成员变量)
(2)使用this关键字调用本类中的成员方法
(3)使用this关键字调用本类中的构造方法
3.5.1 使用this关键字调用本类中的属性
为解决成员变量与构造方法参数的可读性差,需将变量统一命名,会造成成员变量与局部变量同名,导致名称冲突。
例子3-9: 成员变量与局部变量同名,名称冲突
class Student {
private String name; // 定义构造方法
private int age;
public Student(String name,int age) {
name = name;
age = age;
}
public String read(){
return "我是:"+name+",年龄:"+age;
}
}
public class Example09 {
public static void main(String[] args) {
Student stu = new Student("张三", 18);
System.out.println(stu.read());
}
}
我是null,年龄0 (原因:成员变量与参数变量同名,编译器无法确定。解决方法:使用this指代对象属性(成员变量))
例子3-10: this调用本类成员变量
class Student {
private String name; // 定义构造方法
private int age;
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String read(){
return "我是:"+name+",年龄:"+age;
}
}
public class Example09 {
public static void main(String[] args) {
Student stu = new Student("张三", 18);
System.out.println(stu.read());
}
}
我是张三,年龄18
3.5.2 使用this关键字调用本类中的成员方法
例子:this调用本类成员变量
class Student {
public void openMouth(){
.....
}
public void read(){
this.openMouth(); //使用this调用本类成员方法,此处this可缺省
}
3.5.3 使用this关键字调用本类中的构造方法:
原理: 构造方法在实例化对象时,被系统自动调用。若要调用其他构造方法,必须使用this关键字来处理。
语法:
this(参数1,参数2.....)
例子3-11 this调用本构造方法
class Student {
private String name;
private int age;
public Student () { //无参构造方法
System.out.println("实例化了一个新的Student对象。");
}
public Student (String name,int age) { //有参构造方法
this(); // 调用无参的构造方法
this.name = name;
this.age = age;
}
public String read(){
return "我是:"+name+",年龄:"+age;
}
}
public class Example11 {
public static void main(String[] args) {
Student stu = new Student ("张三",18); // 实例化 Student对象
System.out.println(stu.read());
}
}
实例化了一个新的Student对象。
我是:张三,年龄:18
注意:this调用构造方法注意点
(1)只能在构造方法中,使用this调用其他构造方法;不能在成员方法中,使用this调用其他构造方法
(2)在构造方法中,使用this调用其他构造方法,必须位于第一行且只能出现一次;
public Student(String name) {
System.out.println("实例化了一个新的Student对象。");
this(name) ; //错误,必须在第一行
}
(3)不能在同一个类中的两个不同构造方法中使用this相互调用(原因:死循环)
class Student {
public Student () {
this("张三"); // 调用有参的构造方法
System.out.println("无参构造方法被调用了。");
}
public Student (String name{
this(); // 调用无参的构造方法
System.out.println("有参构造方法被调用了。");
}
}
3.6 代码块
定义:“{}”括起来的一段代码
种类(4类):根据声明关键词和位置:普通代码块、构造代码块、静态代码块、同步代码块
3.6.1 普通代码块
定义:直接在方法或语句中,定义的代码块
作用:限定作用域
例子
public class Example12{
public static void main(String[] args) { //main()方法后,普通代码块
{ //局部代码块:在方法中定义的代码块
int age=18; //局部变量,只在此局部代码块起作用
System.out.println("这是局部代码块。age:"+age);
}
int age=30;
System.out.println("age:"+age);
}
}
3.6.2 构造块(构造代码块)
定义:类中直接定义的代码块,与成员变量、成员方法和构造方法同级别。
作用:每次实例化对象时,由系统自动调用构造块。
优于
执行顺序: 构造块------->构造方法,且与两者在类中定义位置无关
例子3-12: 构造快
class Student{
String name; //成员变量
{ //构造代码块,与成员、构造方法同级别
System.out.println("我是构造代码块");
}
public Student(){ //构造方法
System.out.println("我是Student类的构造方法");
}
}
public class Example12 {
public static void main(String[] args) {
Student stu1 = new Student(); //创建两个对象
Student stu2 = new Student();
}
}
我是构造代码块
我是Student类的构造方法
我是构造代码块
我是Student类的构造方法
3.7 static关键字
声明(定义)类,只是描述某类事物的特征(成员变量)和行为(成员方法),并没有产生数据。
只有通过new关键字创建对象时,才会开辟栈内存(对象变量名)和堆内存(对象属性)。
定义:如果类中的某些属性(成员变量),被所有对象共享,将属性(成员变量)声明时,使用static关键字修饰
3.7.1 静态属性:
定义:使用static关键字修饰的属性(成员变量),又称公有属性,全局属性。
作用:只会分配一块内存空间,被所有对象共享,只要修改一次,全部对象该该属性值会发生改变。
静态属性,访问语法:
方法1(类调用静态属性):类名.静态属性名 (推荐:不需要创建对象)
方法2(对象调用静态属性):对象名.静态属性名(必须创建对象)
例子3-13: 静态属性
class Student {
String name; // 定义name属性
int age; // 定义age属性
String school; // 定义school属性
public Student(String name,int age, String school){
this.name = name;
this.age = age;
this.school=school;
}
public void info(){
System.out.println("姓名:" + this.name+",年龄:" +this. age+",学校:" + school);
}
}
public class Example13 {
public static void main(String[] args) {
Student stu1 = new Student("张三",18, "A大学"); // 创建学生对象
Student stu2 = new Student("李四",19, "A大学");
Student stu3 = new Student("王五",20, "A大学");
stu1.info();
stu2.info();
stu3.info();
}
}
例子3-14:静态属性
class Student {
String name; // 定义name属性
int age; // 定义age属性
static String school; // 定义school静态属性
public Student(String name,int age,String school){
this.name = name;
this.age = age;
this.school=school;
}
public void info(){
System.out.println("姓名:" + this.name+",年龄:" +this. age+",学校:" + school);
}
}
public class Example13 {
public static void main(String[] args) {
Student stu1 = new Student("张三",18,"A大学"); // 创建学生对象
Student stu2 = new Student("李四",19,"A大学");
Student stu3 = new Student("王五",20,"A大学");
stu1.school="B大学"; //对象访问静态属性 //Student.school="B大学";类名访问静态属性(推荐)
stu1.info();
stu2.info();
stu3.info();
}
}
注意:static只能修饰成员变量,不能修饰局部变量(编译器报错)。
public class Student{
public void study(){
static int num=10; //编译器报错
}
}
姓名:张三,年龄:18,学校:B大学
姓名:李四,年龄:19,学校:B大学
姓名:王五,年龄:20,学校:B大学
3.7.2 静态方法
若想使用类中的成员方法,必须实例化对象。
定义:使用static关键词修饰的成员方法,
作用:不用实例化对象,通过类名直接调用某个成员方法。
静态方法,访问语法:
方法1(类调用静态方法):类名.静态方法名 (推荐,不需要创建对象)
方法1(对象调用静态属性):对象名.静态方法名 (必须创建对象)
说明:静态方法只能访问静态成员(静态成员变量、静态成员方法),不能访问非静态成员。(非静态成员,需创建对象才能访问)
例子3-15:静态方法
class Student {
private String name; // 定义name属性
private int age; // 定义age属性
private static String school = "A大学"; // 定义school属性
public Student(String name,int age){
this.name = name;
this.age = age;
}
public void info(){
System.out.println("姓名:" +this.name+",年龄:" + this.age+",学校:" + school);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static String getSchool() {
return school;
}
public static void setSchool(String school) {
Student.school = school; //类名调用静态属性
}
}
class Example15 {
public static void main(String[] args) {
Student stu1 = new Student("张三",18); // 创建学生对象
Student stu2 = new Student("李四",19);
Student stu3 = new Student("王五",20);
stu1.setAge(20);
stu2.setName("小明");
Student.setSchool("B大学"); //类名调用静态方法
stu1.info();
stu2.info();
stu3.info();
}
}
3.7.3 静态代码块
定义:类中直接定义的使用static关键字修饰的代码块。
作用:通常对成员变量初始化(赋值)。
执行:静态代码块在类加载时执行,且只执行一次(类只加载一次)
优于 优于
顺序: 静态代码块------>构造块------>构造方法
例子3-16:静态代码块
class Student{
String name; //成员属性
{
System.out.println("我是构造代码块");
}
static {
System.out.println("我是静态代码块");
}
public Student(){ //构造方法
System.out.println("我是Student类的构造方法");
}
}
class Example16{
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
}
}
我是静态代码块
我是构造代码块"
我是Student类的构造方法
我是构造代码块
我是Student类的构造方法
我是构造代码块
我是Student类的构造方法
菜单
本页目录