【Java基础系列】第5章 面向对象(上)

5.1 类和对象

5.1.1 类和对象定义

类:是对某种事物的抽象描述(泛指自然界某一类事物)

实例(对象):是指真实存在的(通过new创建,具体某个事物)

5.1.2 类的组成

成员变量

行为方法

构造器 ----->初始化

初始化块 ----->类初始化时,要做的事情

内部类

5.1.3 类的定义格式

[修饰符] [类名] {

0-N 成员变量

0-N 行为方法

0-N 构造器

0-N 初始化块

0-N 内部类

}

5.1.4 类修饰符

①权限修饰符(2选1):public 、 [默认] //包权限修饰符(不填)

②(2选0-1):abstract //抽象 、 final //最终,不可变

Ps:在同一个java文件,最多定义一个public类,这个public类必须个文件名相同

5.2 成员变量与局部变量

5.2.1 成员变量
成员变量是指在类中定义的变量,也就是指属性,其作用域是在整个类中有效。成员变量在定义时可以不指定初始值,系统可以按默认原则初始化,具体初始化原则如下:

基本类型的默认值为 0,boolean类型为false,复合类型的默认值为null

Byte = 0    Short = 0    Int = 0    Long = 0L      Boolean = false

Float = 0.0f  Double = 0.0d   Char =‘\u0000’  其他类型(引用类型)= null

(1)初始化:可以不初始化,系统会自动初始化

(2)作用域:整个类当中都能使用(无论从哪里开始定义)

(3)成员变量可以放置在类中的任何位置,不能放置在方法或初始化块中

(4)除了abstract不能用,其他修饰符都可以用

5.2.2 局部变量

局部变量一般是指在方法体内部定义的变量,其作用域是在方法块内部有效。局部变量在使用时,必须先初始化然后才能使用,否则程序则不能通过编译,错误示例代码如下:

public class Test{

public void f1(){

int i; // 变量i未初始化,编译将产生错误

// int i = 0; 正确的使用方法

System.out.pringtln(i);

}

}

  1. 形参:

初始化:不作初始化

作用域:代码块开始到结束

  1. 方法中定义的变量:

初始化:定义时必须显式初始化

作用域:从变量定义并 初始化 开始到 方法结束

  1. 代码块中的变量: 如:for(int i=0;i<n;i++){ } 中的i

初始化:定义时必须显式初始化

作用域:代码块开始到结束

5.2.3 成员变量和局部变量的区别

  1. 修饰符不同:

成员变量可以被 public,protect,private,static等修饰符修饰,而局部变量不能被控制修饰符及 static修饰;两者都可以定义成final型。

  1. 存储的位置不同:成员变量存储在堆,局部变量存储在栈。
  2. 作用域不同:

局部变量的作用域:仅限于定义它的方法,在该方法的外部无法访问它。

成员变量的作用域:在整个类内部都是可见的,所有成员方法都可以使用它。如果访问权限允许,还可以在类的外部使用成员变量。

  1. 生存周期不同:

局部变量:生存周期与方法的执行期相同。当方法执行到定义局部变量的语句时,局部变量被创建;执行到它所在的作用域的最后一条语句时,局部变量被销毁。

成员变量:如果是实例成员变量,它和对象的生存期相同。而静态成员变量的生存期是整个程序运行期。

(5)默认值:

成员变量:有默认值,基本类型的默认值为 0,复合类型的默认值为null。(被final修饰且没有static的必须显式赋值)

局部变量:不会自动赋值,所以局部变量在定义后先要赋初值,然后才能使用。

(6)优先级:

局部变量可以和成员变量同名,且在使用时,局部变量具有更高的优先级。

5.2.4 变量初始化的顺序

[1]变量定义位置------>[2]初始化块------->[3]构造器

例:

5.3 方法

5.3.1 定义

(1)格式:

void类型无参方法: 修饰符 void 名字(){执行代码}

void类型有参方法: 修饰符 void 名字(参数列表){执行代码}

有类型无参方法:    修饰符 数据类型 名字()   { 执行代码; return 值;}

有类型有参方法:    修饰符 数据类型 名字(参数列表)  { 执行代码; return 值; }

例子:

//参数列表为不确定参数个数

Public void test(String...args){ }

//数组作参数

Public void test(String[] args){ }

(2)有参方法的返回值:

  • 必须与方法类型匹配或它的子类
  • 无分支语句就一个return,有则可多个return
  • 可返回字面值、变量、表达式、方法(或多个方法结合)

修饰符:

final、abstract只能选一、其他的修饰符都可以用

(3)构造方法:

无参构造方法:修饰符 名字(){执行代码}                    

                 //每个类只能有一个

有参构造方法:修饰符 名字(参数列表){执行代码}

                //每个类可以有多个有参构造方法,但是参数类型必须不一样

跟类名相同

不能指定返回值,void也不能要

修饰符:public 、 protected 、 [默认] 、private

5.3.2 使用

(1)方法定义与使用的流程:①定义方法 ②写代码 ③调用运行

(2)可变参数:

     方法的可变参数表示多个同类型的参数;可变参数只能写在参数列表的最后一位;传递的实际参数也可以是数组。

 例子:public class A7_MethodParameters{

public static void main(String[] args){

String[] str={"请","叫","我","富","豪","!"};  //自定义String数组

A7_MethodParameters amp = new A7_MethodParameters();

System.out.println("============可变参数多个String=============");

amp.method(20,1000000,"请","叫","我","富","豪","!");

System.out.println("=============可变参数使用数组===============");

amp.method(25,9000000,str);

}

//该方法中的参数列表使用了可变参数String...name

public void method(int age,double money,String...name){

System.out.println("年龄: " + age);

System.out.println("资产: " + money + "亿美元");

for(String n : name){     //循环遍历输出可变参数

System.out.print(n + " ");

}

System.out.println();

}

}

5.3.3 值传递

值复制:值复制后修改值不影响原来的值

  (基本类型的数据拷贝的是数据,在方法栈退出后,上一栈的传入参数不受影响)

地址赋值:地址复制后修改地址中的值,该地址的值改变

  (引用类型的数据拷贝的是引用)

5.3.4 方法的重载

(1)概念与定义格式

同一个类内,方法名字一样,参数不一样(同类里方法重载)

如:public void f(){执行代码}

public void f(int i){执行代码}

public void f(int i,String s){执行代码}

public void f(String s,int i){执行代码}

(2)特性

  1. 参数类型不同,构成重载
  2. 参数个数不同,构成重载
  3. 参数顺序不同,构成重载
  4. 与返回值类型无关
  5. 与访问修饰符无关

Ps:注意包装类与基本类型作为参数的时候,两个类型不属于同一种类型,可以作为方法重载的两种不同的参数类型。

如:Integer 和 int

(3)与方法重写的区别

位置

方法名

参数

返回值

访问修饰符

方法重写

子类

相同

相同

相同或小

不能比父类更严格

方法重载

本类

相同

不同

相同或不相同

相同或不相同

5.3.5 递归方法

  1. 阶乘问题

//递归计算5!

class CountTest{

public static void main(String[] args){

CountTest ct = new CountTest();

System.out.println("5!="+ct.count(5));

}

//递归计算5!

public int count(int a){

if(a == 1){

return 1;

}else{

return count(a-1)*a;

}

}

}

  1. 汉诺塔问题

/*

4、汉罗塔问题

*/

import java.io.BufferedReader;

import java.io.InputStreamReader;

public class A6_TaskFourHanoi{

    public static void main(String args[]) throws Exception {

        int n;

//通过IO流来实现键盘输入

        BufferedReader buf =

                new BufferedReader(new InputStreamReader(System.in));

        System.out.print("请输入盘数:");

//将盘的个数从键盘输入,然后记录下来

        n = Integer.parseInt(buf.readLine());   

A6_TaskFourHanoi hanoi = new A6_TaskFourHanoi();

        hanoi.move(n, 'A', 'B', 'C');

     }

  //递归方法,先找到n==1时候的最内层,再一层一层往外。

    public static void move(int n, char a, char b, char c) {

        if (n == 1)

            System.out.println("盘 " + n + " 由 " + a + " 移至 " + c);

        else {

move(n - 1, a, c, b);

            System.out.println("盘 " + n + " 由 " + a + " 移至 " + c);

            move(n - 1, b, a, c);

         }

     }

 }

5.4 构造方法与语句块

5.4.1 构造方法

1.1this:看上去,用来区分局部变量和成员变量同名的情况

1.2this:也可以代表本类对象,this代表他所在函数(方法)所属对象的引用

1.3构造方法之间的调用只能通过this语句来完成

1.4构造方法之间进行调用时,this语句只能出现在第一行,初始化要先执行,如果初始化中还有初始化,那就先执行最内层初始化,再往外执行

1.5构造方法不能交叉调用(即不能在二调用三的同时,三调用二)每个构造方法只能调用一个构造方法

(1)定义格式:修饰符 类名 ( 形参列表 ){ }

(2)特性:

①构造器的命名:与类名相同

②构造器不能有返回类型,也不能有void

③构造器也是一种特殊的方法

④不能写return在构造器内

⑤有返回一个对象this的引用

⑥构造器可以有0-N个

⑦普通方法能与构造器同名,但一定要按照方法规则

⑧如果没有指定构造器,系统会自动创建一个”参数为空”的构造器

⑨如果有指定的“有参”构造器,则需要自己定义“参数为空”的构造器

⑩普通方法内不能用this( )调用构造器

5.4.2 语句块

对象一建立就运行了,而且优于构造方法执行

2.1作用:给对象初始化

2.2与构造方法的区别:

①构造方法使对应的对象进行初始化

构造代码块是给所有对象进行统一的初始化

2.3构造代码块中定义的是不同对象共性的初始化内容

2.4方法内的代码块只在方法被调用时执行

(1)定义格式: 静态语句块    static{ 执行代码 }

                  非静态语句块    { 执行代码 }

(2)语句块的应用场合:当已调用类时,就希望该类执行一些代码,就可以用语句块

(3)语句块里能写:   常量(不能用static修饰)

变量

条件语句

运行普通方法

类(不能添加修饰符)

语句块(非静态语句块定义数据)

(4)静态语句块与非静态语句块区别

静态语句块在非静态语句块之前运行,在类编译时已经编译运行了

静态语句块里运行的代码都是静态的,在内存里有固定的位置

(5)构造方法和语句块的异同

相同:应用场合相似,都是一调用这个类就可以执行一些代码

不同:1.语句块在构造方法之前运行

ps:构造方法中的super()在非静态语句块之前被调用

              2.构造方法可以在调用时传参,语句块不可以

5.5 类成员

static 关键字修饰的成员就是类成员,类成员有类变量、类方法、静态初始化块三个成分,static 关键字不能修饰构造器。static修饰的类成员属于整个类,不属于单个实例

5.5.1 理解类成员

定义:static修饰的成员称类成员。

Ps:可以通过类引用访问,但推荐直接类访问。因为类引用访问是通过该类来访问。类成员(包括方法、初始化块、内部类、枚举类)不能访问实例成员(包括成员变量、方法、初始化块、内部类、枚举类)。因为类成员属于类的,类成员的作用域比实例成员大,而且完全可能类成员实例化完成了,实例化成员还没实例化。

  1. 类变量

定义:static修饰的成员变量称为类变量

调用(不需new):类名.类变量  (在本类内调用可直接 类变量)

  1. 类方法

定义:static修饰的方法称为类方法

调用(不需new):类名.类方法  (在本类内调用可直接 类方法)

Ps:因为类成员是所有实例都共用的,要注意值修改问题

当使用引用来访问类成员时,实际上依然是委托给该类来访问类成员,因此,即使某个引用为null,它也可以访问它所属类的类成员。如:

public class A9_ClassMumber{

//static修饰的类方法

public static void test(){

System.out.println("static修饰的类方法");

}

public static void main(String[] args){

//定义一个A9_ClassMumber变量,其值为null

A9_ClassMumber cm=null;

//使用null对象调用所属类的静态方法(可成功调用)

cm.test();

}

}

上面程序可以正常编译、执行,成功调用static修饰的类方法,这表明null对象可以访问它所属类的成员。

  1. 静态初始化块

在类初始化阶段,系统会调用该类的静态初始化块来对类进行初始化。一旦给类初始化结束后,静态初始化块永远不会再执行。

5.5.2 单例(Singleton)模式

  1. 定义:如果一个类始终只能创建一个实例,则这个类被称为单例类
  2. 分类:①懒汉式、②饿汉式

①懒汉式

例子:public class A9_SingletonTest{

public static void main(String[] args){

//创建Singleton对象不能通过构造器

//只能通过getInstance方法来得到实例

Singleton s1 = Singleton.getInstance();

Singleton s2 = Singleton.getInstance();

 //因为只能创建一个对象,所以引用的地址一样

System.out.println(s1 == s2);  

}

}

//单例类:懒汉式

class Singleton{

//使用一个类变量来缓存曾经创建的实例

private static Singleton instance;

//对无参构造方法使用private,隐藏该构造方法

private Singleton(){

}

//提供一个静态方法,用于返回Singleton实例,

//该方法可以加入自定义控制,保证只产生一个Singleton对象

//将不会重新创建新的实例

public static Singleton getInstance(){

if(instance == null){

//创建一个Singleton对象,并将其缓存起来

instance = new Singleton();

}

return instance;

}

}

②饿汉式

例子://单例模式:饿汉式

public class A11_SingletonTest{

public static void main(String[] args){

//创建Singleton对象不能通过构造器

//只能通过getInstance方法来得到实例

Singleton instance1 = Singleton.getInstance();

Singleton instance2 = Singleton.getInstance();

Singleton instance3 = Singleton.getInstance();

//因为只创建了一次对象,所以引用的地址一样

System.out.println( (instance1 == instance2) );

System.out.println( (instance1 == instance3) );

}

}

//单例类:饿汉式

class Singleton{

//使用一个类变量来创建一个实例

private static Singleton instance = new Singleton();

//对无参构造方法使用private,隐藏该构造方法

private Singleton()

}

//提供一个静态方法,用于返回Singleton实例,

public static Singleton getInstance(){

return instance;

}

}

5.6 继承

作用:为了类的复用、和扩展而设计的

5.6.1 格式

      类与类 : 类名 extends 要继承的类名

      接口与接口:  接口 extends 要继承的接口名,要继承的接口名,......

5.6.2 特性

(1)用在类与类或者接口与接口之间

(2)一个对象继承另一个对象之后,这个对象就具有了另一个对象的全部特征,当然还要根据访问权限,private修饰的无法访问,默认修饰符的也只能是同包的子类访问

(3)注意:在类与类之间,不能同时直接继承多个,可以间接继承;在接口与接口之间可以。

(4)当子类和父类的数据相同时,父类的数据将会被子类数据覆盖掉。但不能覆盖无参构造方法和语句块,即子类和父类的无参构造方法和语句块同时存在。

(5)如果要调用所继承类里的数据,我们可以用super.要调用的数据,但super.不能调用构造方法、语句块和内部事物

(6)子类继承父类,子类中可以用的父类属性(非静态)、方法(非静态)都是父类的引用中的属性、方法(即子类使用的父类属性、方法属于父类引用的)

(7)final修饰的类不能被继承

(8)子类和父类都有的用子类,子类没父类有的用父类;但调用父类独有的方法时,该方法中使用的属性父类、子类都有,则还是默认调用父类的属性。(父类的东西可以理解为子类自己的东西)

例如://输出结果为name = "Parent"的值

public class A14_ExtendsGetValue{

public static void main(String[] args){

Child c = new Child();

System.out.println( c.getName() );  //子类调用父类独有的方法

}

}

//父类

class Parent{

protected String name = "Parent";   //父类的属性

public String getName(){  //父类独有的方法

return name;          //返回的的父类的属性

}

}

//子类

class Child extends Parent{

protected String name = "Child";   //与父类相同名字的属性

}

5.6.3 子类与父类构造器的调用规则

 (子类代表当前类,父类代表所继承的类)

(1)子类和父类都有无参和有参构造方法的情况:

      ①用无参(有参)构造调用子类,会先运行父类无参构造方法,

        再运行子类无参(有参)构造方法。

 (2)父类只有有参构造方法,子类有无参和有参构造方法的情况:

      ①要在子类的无参和有参构造方法里的第一行加上:super(参数);

      ②用无参(有参)构造调用子类,会先运行父类有参构造方法,

        再运行子类无参(有参)构造方法。

5.6.4 方法重写

  (1)在类里,如果要改写继承过来的普通方法,可以用方法重写,步骤如下:

     ①先点击右键,选择Sourse下的Override选项

     ②再选择你要改写的方法,直接在生成方法里写代码

  1. 方法重写:在子类中覆盖了父类的方法的条件

两同两小一大:①方法名相同

                      ②参数列表完全相同

                      ③返回值类型比父类返回值类型小或相同(子类重写方法的返回值类型必须为父类方法的返回值类型,或是父类方法返回值类型的子类类型)

                      ④子类方法声明抛出的异常比父类抛出的异常小或相同

                 ⑤子类方法的修饰符权限比父类的大或相同(父类方法需非private)

静态方法不能被覆盖成非静态方法

(3)构造方法不能被继承,因此不能被重写

①在子类中调用父类构造方法:

格式:

super();  //只能是构造方法中的第一条,用于调用父类的一个构造方法

super(参数);

Ps:1.没写super()时,子类构造方法中第一行默认调用父类构造方法。

2.当子类构造方法被调用时,父类以及父类的父类等等,都会被调用,直到最顶 层的父类,其构造方法都被调用。

②子类中调用父类属性和方法:

格式:

super.父类属性或方法  //区别于子类本身的属性、方法调用

例如:父类、子类都有同一个属性 String name时

super.name;  //调用父类的name

name;        //调用子类的name

5.6.5 this与super  

(1)this

是指向本类的实例的引用

当前类的调用,通过this可以调用当前类的量和方法

(this不能在静态方法里使用)

不管是否写this,在访问本类成员时,都默认已加上this

方法内不能使用this()调用构造器

例1:

//this 访问本类非静态成员

class A{

int score;

public void test(){

this.score;

this.test2();

}

public void test2(){

}

}

例2:

//this调用本类的构造器

Class B{

int age;

public B(){

}

public B(){

this(); //调用无参构造器

}

}

例3:

//在一个方法中返回 this, 可供外界获取这个实例的引用

public class ThisTest

{

int count;

//increase()方法返回this 即本方法体

public ThisTest increase(){

count ++;

System.out.println( "increase[1] --> count: "+ count );

//在一个方法中返回 this, 可供外界获取这个实例的引用

return this;

}

//increase2()方法返回this 即本方法体

public ThisTest increase2(){

count += 2;

System.out.println( "increase[2] --> count: "+ count );

return this;

}

//主方法

public static void main(String[] args){

ThisTest tt = new ThisTest().increase().increase2().increase();

System.out.println( "count: "+ tt.count );

}

}

(2) super和this的异同

  1)super(参数):调用基类(父类)中的某一个构造函数(应该为构造函数中的第一条语句) 

       2)this(参数):调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)
3)super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名    super.成员函数据名(实参)

4)this

在类的方法定义中使用this关键字代表使用该方法的对象的引用,this可以看做一个变量,值是当前对象的引用;它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)

    5)调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。

   6)super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。

7)super()和this()均需放在构造方法内第一行。

8)尽管可以用this()调用一个构造器,但却不能调用两个。

9)this()和super()不能同时出现在一个构造函数里面,因为this()必然会调用其它的构造函数,其它的构造函数必然也会有super()语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。

10)this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。

   11)从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

5.7 多态

5.7.1 概念及特性

(1)多态概念:用基类的引用指向子类的对象

(2)多态必备条件:①编译类型与运行类型不同

 ②拥有继承关系的类

(3)多态的作用:方便后期扩展类的使用而设计

(4)多态的两个好处:

①应用程序不必为每个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承

②派生类的功能可以被基类的方法或引用变量所调用,这叫后兼容。可以提高可扩充性和可维护性。       //多态的真正作用

(5)多态在什么地方用:①方法的参数中

②方法的返回值类型中

Ps:引用变量只能调用声明该变量时所用类里包含的方法,如:Object p = new Person();

引用变量p只能调用Object类的方法,而不能调用Person类里定义的方法。

5.7.2 引用变量的强制类型转换

①用处:

父类引用 = 子类引用;        //自动转化

子类引用 = (子类)父类引用;  //需要强转

例子:class Dog extends Animals{

          Public static void main(Stringp[] args){

  Dog dog = new Dog();                //实例化Dog类引用dog

  Animals animal_animal = new Animals(); //实例化Animals类

  Aniamls animal_dog = new Dog();//多态,Animals类引用Dog类实例化

          //  dog = (Dog)animal_animal; //报错,因为运行类型为Animals类

  dog = (Dog)animal_dog;    //正确,因为运行类型为Dog类

       }

  }

①作用:如果需要让多态实例化出来的引用变量调用它运行时类型的方法,则必须把它强制类型转换成运行时类型,强制类型转换需要借助于类型转换运算符。

②类型转换运算符用法:(type)variable  //可将一个引用类型变量转化为其子类类型

③引用类型之间的转换条件:只能在具有继承关系的两个类之间进行。

5.7.3 instanceof 运算符

(1)格式: boolean b = A类对象 instanceof B类或接口 ;    //返回boolean型

(2)作用: 判断“前面的对象”是否是“后面类、其子类、接口”的实例;一般用于强制类型转换之前的判断,这样会更加安全,同时保证程序更加健壮。

5.8 封装

5.8.1包

import作用:添加一个import导入你要关联的对象所在包。

  1. 创建包:

①规则:都为小写字母,一般如:com.java   //每个.就一层文件夹

②定义格式:package 包名;   //定义包,必须在源文件的第一行

例如:package com.java;

  1. 导入包:

① 定义格式:import 包名.类名/*;

例如:import java.util.Scanner;  //导入util包中的Scanner类

import java.util.*;         //导入util包中的所有类

 import java.util.System.out;  //导入util包中System类中的out方法

② 直接使用:

例如:java.util.Arrays.toString(arr);  //将整个数组转为String型

  1. 静态导入:

格式:import static 包名;

例如:import static java.lang.*;   //只能使用lang包的静态成员

特性:只能使用该包内的静态属性和静态方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__Yvan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值