JavaSE - 04 面向对象

发布于:2023-01-15 ⋅ 阅读:(539) ⋅ 点赞:(0)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


1.类与对象

1.1 面向过程(pop)与面向对象(oop)

面向过程(pop): 面向过程是以过程为中心的,每一步都是自己实现的。

面向对象(oop): 面向对象是以对象为中心的,通过指挥对象来实现。

1.2 类与对象

类: 类是对一类事务的具体描述,是一组行为和属性的集合,是抽象的。
对象: 对象是该类的一个具体表现形式,是实际存在的,也称为实例,是具体的。
关系: 类是对象的模板,对象是类的实体。

类的结构:

属性:指代事务的特征,在类中通过成员变量来体现。
行为:指代的是执行的操作,在类中通过成员方法体现的。
构造器
代码块
内部类

1.3 类与对象的定义与使用

①、类的定义格式:

[权限修饰符] class 类名{
    属性;
    行为;
}

// 例如,建立一个学生类Student
class Student{
    
}

② 、成员属性定义格式:[权限修饰符] 数据类型 成员变量名 = 值;

// 例如:在学生类中添加姓名、年龄属性
class Student{
    String name;
    int age;
}

③、对象的创建格式: 类名 对象名 = new 类型();

// 例如在主方法内创建一个学生对象
public class Demo01 {
    public static void main(String[] args) {
        // 创建对象: 类名 对象名 = new 类名();
        Student student = new Student();

    }
}
// 学生类
class Student{
    String name;
    int age;
}

④、成员属性的调用:

静态: 类名.属性名

非静态: 对象名.属性名

public class Demo01 {
    public static void main(String[] args) {
        // 创建对象: 类名 对象名 = new 类名();
        Student student = new Student();

        // 使用成员属性
        student.name = "张三";
        student.age = 10;
        System.out.println("student.name = " + student.name); //student.name = 张三
        System.out.println("student.age = " + student.age);//student.age = 10

    }
}

class Student{
    String name;
    int age;
}

⑤、成员方法的调用:

静态: 类名.方法名(参数)

非静态: 对象名.方法名(参数)

public class Demo01 {
    public static void main(String[] args) {
        // 创建对象: 类名 对象名 = new 类名();
        Student student = new Student();
        // 方法的调用
        student.method();
    }
}

class Student{
    public void method(){
        System.out.println("方法");
    }
}

⑥、匿名对象

我们也可以不定义对象的句柄,而直接调用这个对象的方法。这 样的对象叫做匿名对象。 如:new Person().shout();
使用情况 :如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。 我们经常将匿名对象作为实参传递给一个方法调用。

⑤、对象内存分析图:
在这里插入图片描述

1.4 方法

概述: 用来完成某一个特定的功能的代码块。

定义的格式

[权限修饰符] [static] 返回值类型 方法名(参数列表){
	方法体;
	return 返回值;
}

// 代码实例
public void method(){
    System.out.println("方法");
}

注意事项:

a、方法是平级的,不可以嵌套使用。

c、方法被调用一次,才会被执行一次。

d、方法的返回的结果是返回给调用者,结果由调用这进行处理。

e、没有返回值的方法,返回值类型是void,可以不写return语句,但系统会默认添加一个return。

方法的重载:

概述:在同一个类中,允许出现一个或一个以上方法名相同的方法,他们的参数列表(参数的个数\参数类型)不同,称为方法的重载。
注意事项:方法的重载与返回值类型无关。

public class Demo01 {
    public static void main(String[] args) {
        Sum sum = new Sum();
        sum.getSum(1,2);
        sum.getSum(1,2,3);
        sum.getSum(1.0,2.0);
        sum.getSum(1.0,2.0,3.0);
    }
}

/**
 * 定义一个方法,对不同的数据类型,不同参数个数 求和
 */
class Sum{
    public void getSum(int a , int b){
        System.out.println("int : a + b = " + ( a + b ));
    }


    public void getSum(int a , int b ,int c){
        System.out.println("int : a + b + c = " + (a + b + c));
    }

    public void getSum(double a , double b){
        System.out.println("double : a + b = " + ( a + b ));
    }

    public void getSum(double a , double b ,double c){
        System.out.println("double : a + b + c = " + (a + b + c));
    }
}

可变参数:

/**
 * 概述:JavaSE1.5版本定义了一个Varargs机制,允许直接定 义能和多个实参相匹配的形参。
 * 		从而,可以用一种更简单的方式,来传递个数可变的实参。
 * 格式:方法名(数据类型 ... 变量名){}
 * 注意事项:
 * 		可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个
 * 		可变个数形参的方法与同名的方法之间,彼此构成重载
 *  	可变参数方法的使用与方法参数部分使用数组是一致的
 * 		方法的参数部分有可变形参,需要放在形参声明的最后
 * 		在一个方法的形参位置,最多只能声明一个可变个数形参
 */
public class Demo02 {
    public static void main(String[] args) {
        method(1,2,3,4,5,6);
    }
    public static void method(int...a){
        for (int i : a) {
            System.out.println(i);
        }
    }
}

参数传递机制: Java中参数传递的方式只有一种,值传递,就是将值复制给形参。
①、形参是基本数据类型:将实参基本数据类型变量的 数据值 传递给形参,其原内容不会发生变化。
②、形参是引用数据类型:将实参引用数据类型变量的 地址值 传递给形参,其原内容会发生变化。

递归: 方法自己调用自己的过程。

/**
 * 递归
 * 求1-100的阶乘
 */
public class Demo03 {
    public static void main(String[] args) {
        System.out.println("fac(5) = " + fac(5));
    }
    public static int fac(int num){
        // 递归出口
        if (num == 1){
            return 1;
        }

        // 递归规律
        return fac(num - 1) * num;
    }
}

1.5 构造方法(构造器)

构造器的特征:
a.方法名必须与类名保持一致。
b.构造器没有返回值
c.构造器没有返回值类型

执行时机:
实例化对象时,进行加载

构造器的作用:
创建一个对象,并初始化赋值操作

格式:

[权限修饰符] 类名(参数列表){
    方法体;
}

注意事项:
a、每一个类都有一个构造器,没写系统会默认提供一个空参构造。
b、在类中,一旦定义了构造方法,则系统则不再提供构造。
c、在同一个类中,可以重载多个构造方法。
d、子类不能继承父类的构造方法。

public class Demo04 {
    public static void main(String[] args) {
        Student student = new Student();
        Student student1 = new Student("张三");
    }
}
class Student{
    public Student(){
        System.out.println("空参构造");
    }

    public Student(String name){
        System.out.println("带参构造");
    }
}

2.面向对象的三大特征

2.1 封装

封装概述: 隐藏对象内部的复杂性,提供一个简单的访问接口。便于外界调用,从而提高系统的可扩展性和可维护性。 简单的说,该暴露的暴露,该隐藏的隐藏,这就是封装的思想。

封装原则: 将类中的某些信息进行私有化(private),不让外部程序直接访问。而是提供一个公共的访问方法(getXxx、setXxx),对其进行访问。

封装的好处: 提高代码的可扩展性,可维护性,复用性

private关键字:
private 私有的,是一个权限修饰符,被他修饰的成员变量或方法,只能在本类中进行访问。
若想要被其他类访问,需要提供一个公共的访问方法getXxx()\setXxx().

/**
 * 封装一个学生类,将姓名、年龄私有化提供一个公共的访问方法。
 */
public class Demo01 {
    public static void main(String[] args) {
        // 创建学生对象
        Student student = new Student();
        student.setName("张三");
        student.setAge(11);
        System.out.println("student.getName() = " + student.getName());
        System.out.println("student.getAge() = " + student.getAge());
    }
}

class Student{
    private String name;
    private int age;

    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;
    }
}

this关键字

指代的是当前对象的引用
作用:
	1. 在任意方法或构造器内,如 果使用当前类的成员变量或成 员方法可以在其前面添加this, 增强程序的阅读性。不过,通 常我们都习惯省略this2. 当形参与成员变量同名时, 如果在方法内或构造器内需要 使用成员变量,必须添加this来 表明该变量是类的成员变量
	3.使用this访问属性和方法时, 如果在本类中未找到,会从父 类中查找

注意:
	可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其 他的构造器!  
	明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器 
	如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了 "this(形参列表)""this(形参列表)"必须声明在类的构造器的首行! 
	在类的一个构造器中,最多只能声明一个"this(形参列表)"

2.2 继承

概述: 当多个类中具有相同属性和方法时,可以将这些相同的属性和方法抽取到同一个类中,让这些类继承该类,这个过程称为继承。

格式: class 子类 extends 父类{}

public class Demo04 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.fu();
    }
}
class Fu{
    public void fu(){
        System.out.println("父类方法");
    }
}
class Zi extends Fu {
    public void zi(){
        System.out.println("子类方法");
    }
}

继承作用(好处):
①、减少代码的冗余,提高代码的复用性。
②、继承的出现,有利与功能的扩展,提高了可扩展性。
③、让类与类之间产生联系,是多态的前提条件。

继承的弊端: 让类与类之间产生了联系,增加了代码的冗余

继承的特点:
a、Java只能支持单继承,不能支持多重继承。
b、Java支持多层继承。
c、子类继承父类,就继承父类的所有的属性和方法。
d、一个父类可以有多个子类

继承中成员变量访问特点: 采用的是就近原则
子类局部变量范围-》子类成员变量范围-》父类成员变量范围

方法重写:

/**
 * 方法重写
 * 	概述:当子类与父类出现相同的方法声明时(参数列表也必须相同);
 * 		要求:
 * 			a、方法名,参数列表必须相同。
 * 			b、子类返回值类型必须小于或等于父类方法的返回值类型
 * 			c、子类的权限修饰符必须大于等于符类的权限修饰符
 * 			d、子类所抛出的异常不能大于父类的异常
 */
public class Demo05 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }
}
class Fu{
    public void method(){
        System.out.println("父类方法");
    }
}
class Zi extends Fu {
    public void method(){
        System.out.println("子类重写父类方法");
    }
}

方法的重写与方法的重载的区别:

参数列表:方法的重写参数列表必须相同,重载才参数列表必须不同
执行的范围:方法的重写时子类与父类,重载时在同一个类中表现的
返回值类型:方法重写子类的返回值类型可以不同,重载必须相同

super关键字

代表父类存储空间的标识(可以理解成父类的引用)
使用格式:
	super.成员变量:表示当前对象的某个成员变量,该成员变量在父类中声明的
	super.成员方法:表示当前对象的某个成员方法,该成员方法在父类中声明的
	super()super(实参列表):调用父类的构造器协助当前对象的实例化,只能在构造器首行,只会找直接父类的对应构造器,找不到就报错
注意事项:
	a、子类的所有构造器都会默认调用父类的空参构造
	b、若父类没有空参构造,子类构造器中必须通过super(参数列表)\this(参数列表)来调用父类中相应的构造方法。
	   同时二者只能选其一,并且该语句要放在子类构造器中的第一行
	c、若以上条件都没有,则编译器会编译错误

权限修饰符:
在这里插入图片描述

2.3 多态

概述: 同一个对象的不同表现形态,也就是父类指向子类对象

多态的前提条件:
a、类与类之间是继承关系
b、方法要重写
c、父类指向子类对象

成员访问特点:
成员变量:编译时看父类,运行时看父类。
成员方法:编译时看父类,运行时看子类。

多态的好处: 提高代码的通用性和扩展性。

多态的弊端: 不能使用子类的特有成员

多态的转型:

向上转型:当左边的变量的类型(子类) > 右边对象/变量的编译时类型(父类),也就是父类指向子类对象
向下转型:当左边的变量的类型(子类) < 右边对象/变量的编译时类型(父类)
		  格式:子类型 对象名 = (子类型)父类引用;	

多态转型的风险:

如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现 ClassCastException
解决方案:instanceof关键字
变量名 instanceof 类型 
通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果

2.4 其他关键字

static关键字:
		是Java中的一个修饰符。
		特点:
			a、随着类的加载而加载
			b、优于对象存在
			c、可以通过类名调用
			d、被static修饰的变量被该类的所有对象共享。
		注意事项:
			静态可以调用静态
			静态可以调用非静态
			非静态不可以调用静态
	
native关键字:
		ative只能修饰方法,表示这个方法的方法体代码不是用Java语言实现的,而是由C/C++语言编写的。
		但是对于Java程序员来说,可以当做Java的方法一样去正常调用它,或者子类重写它。		
	
final关键字:
		最终的,最后的。
		
		final修饰类,该类不可以被继承。
		final修饰方法,该方法不可以被重写。
		final修饰变量,该变量为常量,赋值完成后,不可以再次赋值。

3.面向对象进阶

3.1 代码块

概述:对Java代码进行初始化操作,用{}括起来的操作。

分类:
	  静态代码块:用static 修饰的代码块 
		可以有输出语句。
	  	可以对类的属性、类的声明进行初始化操作。 
        	不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。 
		若有多个静态的代码块,那么按照从上到下的顺序依次执行。
 		静态代码块的执行要先于非静态代码块。
 		静态代码块随着类的加载而加载,且只执行一次。
	  
     非静态代码块:没有static修饰的代码块
		 可以有输出语句。
		 可以对类的属性、类的声明进行初始化操作。
		 除了调用非静态的结构外,还可以调用静态的变量或方法。
		 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。 
 		 每次创建对象的时候,都会执行一次。且先于构造器执行。

3.2 抽象类

概述: 如果一个类中,有一个或多个方法没有具体的实现方式,那么可以将该方法定义为抽象方法,则该类为抽象类。

抽象类方法的定义:
抽象类:用abstract修饰的类为抽象类
抽象方法:用abstract修饰的方法称为抽象方法。

public class Demo01 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.show();
    }
}

abstract class Fu {
    public abstract  void show();
    public void method(){
        System.out.println("父类方法");
    }
}

class Zi extends Fu{
    @Override
    public void show() {
        System.out.println("子类重写父类的抽象方法");
    }
}

抽象类的特点:

抽象类的特点:
	a、抽象类和方法必须用abstract关键子修饰
		格式:public abstract 类名{}
		   public abstract 返回值类型 方法名(参数列表);
	b、抽象类不可以被实例化
	c、抽象类中可以没有抽象方法,但有抽象方法的类一定是抽象类
	d、若一个子类继承了抽象类:
		普通类:则重写父类所有的抽象方法。
		抽象类:可以不重写,也可以部分重写。	
	e、抽象类中可以有构造方法

3.3 接口(interface)

概述: 本质是契约,标准,规范,就像我们的法律一样。

接口的特点:
①、接口用关键字interface修饰
②、子类实现接口用implements实现
③、子类实现接口要么子类是抽象类,要么重写接口的所有抽象方法
④、接口中没有构造方法
⑤、接口采用多实现机制

接口的成员特点:

​ 成员变量:public static final 进行修饰为常量

​ 成员方法:public abstract 进行修饰

类与接口关系:
①类与类的关系 继承关系,只能单继承,但是可以多层继承
②类与接口的关系 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
③接口与接口的关系 继承关系,可以单继承,也可以多继承

public class Demo02 {
    public static void main(String[] args) {
        Student student = new Student();
        student.eat();
        student.see();

        Teacher teacher =new Teacher();
        teacher.eat();
        teacher.see();
    }
}
// 接口
interface Person{
    public abstract void eat();
    public abstract void see();
}

// 实现类
class Student implements Person{

    @Override
    public void eat() {
        System.out.println("学生吃饭");
    }

    @Override
    public void see() {
        System.out.println("学生看书");
    }
}

// 实现类
class Teacher implements Person{

    @Override
    public void eat() {
        System.out.println("老师吃饭");
    }

    @Override
    public void see() {
        System.out.println("老师看教案");
    }
}

3.4 内部类

概述: 在一个类中定义一个类。

内部类的访问特点:
①内部类可以直接访问外部类的成员,包括私
②外部类要访问内部类的成员,必须创建对象

成员内部类

位置:类中方法外
定义格式:
	[权限修饰符] [static] class 外部类名{
		[权限修饰符] class 内部类名{

		}
	}
访问方式:
	非静态:外部类名.内部类名 对象名 = new 外部类名().内部类名(); 		
	静态::外部类名.内部类名 对象名 = new 外部类名.内部类名();		
					外部类名.内部类名.方法名(); 
注意事项:
	a、非静态的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员。
	b、外部类访问成员内部类的成员需要实例化
	c、内部类可以直接调用外部类的所有成员
	d、当想要外部类的静态成员部分使用内部时,可以考虑内部类声明为静态的

局部内部类

位置:在方法中
定义格式:
	[权限修饰符] 返回值类型 方法名(参数列表){
		[final\abstract] class 类名{
						
		}
	}
					
字节码文件名称:外部类$编号局部内部类名
特点:
	内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但 是前面冠以外部类的类名和$符号,以及数字编号。 
	只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方 都不能使用该类。 
	局部内部类可以使用外部类的成员,包括私有的。 
	局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局 部变量的声明周期不同所致。 
	局部内部类和局部变量地位类似,不能使用public,protected,缺省,private  局部内部类不能使用static修饰,因此也不能包含静态成员

匿名内部类:

概述:匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。
格式:
	new 父类构造器(实参列表)|实现接口(){
		//匿名内部类的类体部分 
	}
			
特点:
	匿名内部类必须继承父类或实现接口
	匿名内部类只能有一个对象 
	匿名内部类对象只能使用多态形式引用

3.5 枚举

定义的格式

	【修饰符】 enum 枚举类名{
   		 常量对象列表
	}

	【修饰符】 enum 枚举类名{
    	常量对象列表;
    
    	其他成员列表;
	}

枚举的特点:

- 枚举类的构造,一定是privatede 
- 枚举类的构造可以是空参构造,可以是有参构造
	* 编译器给枚举类默认提供的是private的无参构造,
	  如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数,
	* 如果枚举类定义有参构造,直接在常量对象名后面加(实参列表)就可以
- 枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写
- 如果常量对象列表后面没有其他代码,那么“;”可以省略,否则不可以省略“;”
- 枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型
- 枚举类重写了Object的toString方法,默认返回的是常量名
- JDK1.5之后switch,提供支持枚举类型,case后面可以写枚举常量名。
- 枚举类型如有其它属性,建议(不是必须)这些属性也声明为final的,因为常量对象   在逻辑意义上应该不可变。

枚举的常用方法:

1.String toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法!
2.String name():返回的是常量名(对象名)
3.int ordinal():返回常量的顺序号,默认从0开始
4.枚举类型[] values():返回该枚举类的所有的常量对象,返回类型是当前枚举的数组类型,是一个静态方法
5.枚举类型 valueOf(String name):根据枚举常量对象名称获取枚举对象

网站公告

今日签到

点亮在社区的每一天
去签到