Java面向对象笔记整理

java面向对象

编程语言的发展

主线:1.以人为本(程序的思维接近于人的思维) 2.如何实现代码的复用

1:) 机器语言(1.0组成): 可读性极差, 把人想象成机器(硬件), 没有什么代码复用

2:)汇编语言(简单英文替换1.0指令): 可读性好一些, 开发人员需要懂硬件, 没有什么代码复用

3:)高级语言

面向过程编程语言: 例如C语言, 重点在于过程(步骤), 在细节,函数 对数据关注不是很高 代码的重用层次: 函数级

面向对象编程语言: 例如java, C#,python… 重点在整体, 在对象上, 这个对象包含什么数据?包含的动作(函数/方法)? 代码的重用层次: 类层次/对象层次

面向对象三大特征:
  • 封装 (Encapsulation)
  • 继承 (Inheritance)
  • 多态 (Polymorphism)

类与对象

对象:

生活中的实体,看得见摸得着的事物都可以看作是对象

类:

一组相同特征的对象的集合,是对对象抽象的描述

对象与类的关系

对象是类的实例化(具体化),类是对象抽象出来的,以类为模板创建对象,使用的是对象而不是类。

类的属性也叫类成员变量,类的方法也叫类的成员函数/成员方法。一个类中的方法可以直接访问同类中的任何成员(包括成员变量和成员函数)
访问修饰符(4个)

public 缺省(默认default) protected private 一般使用public

属性与类的区别

1:)属性是定义在类的大括号中的,变量定义在方法中

2:)属性在整个类中有效,变量只在定义它的方法内部有效

3:)属性有初始值,根据数据类型确定;而变量没有初始值,直接使用时会报错

byte/short/int/long: 0

float/double: 0.0

boolean: false

char: \u000(表示为空)

String ,其他的类类型: null

创建对象 使用对象

类名 对象名 = new 类名();

对象. 属性/方法

什么是测试类

包含main方法的类

面向对象的内存结构图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uIJPbrem-1658545391530)(D:\飞思实训三\课件\笔记\7-19笔记\assets\image-20220719152837645.png)]

局部变量是保存在内存的栈中,而new出来的东西是保存在堆中。也就是说:Person p1 = new Person(); p1是保存在栈中,而且保存的是new Person在堆中的一个地址码,而new Person()是保存在堆中.
属性

名词性描述(方法:动词性描述)

方法

概念:方法是对象的动态的描述, 表示这个对象拥有什么行为或者什么功能,方法是具有独立功能的代码块,不调用就不执行。

作用:提高代码的复用性

类中的方法 不调用不执行

方法的调用

1:)在同一个类中时: 方法名();

public class Student {
	public void a(){
		System.out.println("a方法执行>>>");
	}
	
	public void b(){
		a();//b()方法调用a()方法,只需要直接写a();不需要创建Student类的对象,因为他们都是属于Student类的方法,所以不需要去创建Student类的对象
	}
}

2:)不同类之间调用方法时 : 对象名. 方法名(); 也就是说,当你需要在一个类中调用另一个类的方法,就必须先创建对象,通过对象来调用方法

Student类:

public class Student {
	public void a(){
		System.out.println("a方法执行>>>");
	}
}

Teacher类:

public class Teacher {
	//Teacher类的b()方法调用Student类的a()方法
	public void b(){
		//1.创建Student类的对象
		Student stu = new Student();
		//2.通过对象名.方法名()调用Student类的a()方法
		stu.a();
	}
}
调用有参数的方法时,给参数赋值时,一定要与方法定义的参数类型一样或者是它的子类的类型。参数个数也必须一样(形参的本质是一个局部变量,只在方法内部有效)
调用有返回值的方法时,最好定义一个与返回值类型相同的变量或者数组来接收,如果没有,默认屏蔽
方法常见的错误
  1. 方法不能嵌套,即方法内部不能定义方法,也不能定义属性(但是可以调用方法,可以定义局部变量)

    public void fun1(){
    
       //方法内部定义一个方法, 错误
       /*public void fun2(){
       }*/
    
       //方法内部定义一个属性, 错误
       //public int a;
    
       //定义局部变量 可以
       int a;
    }
    
  2. 方法的返回值类型为void,表示该方法没有返回值,没有返回值的方法可以省略return语句不写,如果要编写return,后面不能跟具体的数据;如果是其他的返回类型,必须要用return返回结果。

    return与break的区别

    break: 结束循环,只能在switch,循环中使用,

    return: 结束方法(可替换break)

    return 结果:先返回结果,再结束方法

    return返回值的问题

    1:)当返回值为void时,用 return 结果 返回,会报错

    2:)return 后面返回多个结果 return 结果1,结果2 ,报错、

    解决方法:1. 返回值类型设置成数组类型 (缺点:只能返回相同类型) 2.把多个数据封装成类,数据作为这个类的属性,返回这个类的对象(推荐使用第二个,面向对象)
    //第一种解决方案: 返回值类型变成数组类型
    public double[] fun3(){
       double  height = 1.75;
       double weight = 70;
       double[] rs  = new double[2];
       rs[0] = height;
       rs[1] = weight;
       return rs;
    }
    
    //第二种解决方案: 把多个数据封装成一个对象,数据作为这个对象的属性
    //返回的是类的对象
    public Person  fun4(){
       double  height = 1.75;
       double weight = 70;
       String name = "张三";
       Person person = new Person();
       person.height = height;
       person.weight = weight;
       person.name = name;
       return person;
    }
    

    定义方法是需要考虑是否要传参

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JkZMzy59-1658545391531)(D:\飞思实训三\博客\我的\java面向对象\assets\image-20220720144042170.png)]

    方法的重载

    在同一个类中一组方法名相同但是参数列表不同的方法,称为重载的方法

    当一个方法需要根据不同的情境输入不同类型的参数时,不需要再额外定义一个具有相同功能而参数列表类型不同的方法。例如我们要使两个数相加,可以定义一个add(int a, int b)方法,此时由于这个方法不能传入double等其他类型的数据,我们可以使用方法重载,即add(double a,double b)等,方法的重载可以让调用者不需要记住一堆方法名, 只需要记住一个方法名就够了

    public class Calculator {
        public int add(int a , int b){
    		return a+b;
    	}
        public double add(double a , int b){
    		return a+b;
    	}
    	public double add( int a ,double b){
    		return a+b;
    	}
    	private void add(){
    		System.out.println(1+2);
    	}
    }//以上都是方法重载
    
    方法重载的条件
    1. 必须在同一个类中, 也就是说add(int a,int b)与add(double a, double b)这两个方法必须在同一个类中
    2. 方法名一样
    3. 参数的个数,或者参数的类型,或者不同类型的参数位置不一样
    4. 与返回值,访问修饰符无关 ,也就是说如果参数列表一样,返回值和访问修饰符不一样,这不是方法的重载。
    jdk 不能同时存在两个相同的方法, 是否是相同方法, jdk如何判断?
    1. 看方法名是否一样, 如果不一样, 肯定不是相同方法
    2. 如果一样, 再判断参数列表是否一样, 如果参数个数一样,并且对应位置的参数数据类型一样, 这就是相同方法, 如果参数列表不一样, 这就是方法重载,

面向对象思维写代码步骤

  1. 问题中包含几个对象? 有几个类?
  2. 每个对象包含哪些属性?
  3. 每个对象包含哪些方法?
  4. 类中的方法是否需要传参?(获取不到的数据需要传参)

构造方法/构造器

当我们创建对象时其实new 类名()就是一个构造方法。如果没有在类中手写构造方法,Java虚拟机会创建一个空的构造方法,格式为

public 类名(){}

如果已经在类中写了构造方法,则Java虚拟机不会创建构造方法了,每创建一个对象,都会自动调用一次构造方法

idea 自动生成构造方法: alt + insert键

作用: 创建对象, 也有对对象属性进行初始化操作
构造方法区别于一般方法的特征
  • 构造方法名与类名相同

  • 构造方法没有返回值这一说法

  • 构造方法不能在方法中用return 语句返回一个值

语法
[访问修饰符] 类名(参数列表){
    //方法体
}
调用构造器(隐式返回创建的类的对象)

通过new关键字调用, new 构造方法();返回创建的类的对象

构造方法的作用

类的构造方法可以为类的所有实例对象的成员变量进行初始化操作,当一个类的实例对象刚产生时,也就是当我们new一个实例对象时,构造方法会自动被调用,可以在该方法中写入要完成的初始化操作。构造方法还可以创建对象

构造方法的名称和类的名称为什么要相同呢?

这是因为构造方法由Java编译器负责调用,而编译器必须知道哪一个才是构造方法,采用与类同名的方式应该是最简单合理的。

注意:
构造方法不含返回值的概念是不同于”void“的,对于public void 类名(){}这样的写法不再是一个构造方法,而是一个普通方法

构造方法的重载

和一般的方法重载一样,它们具有不同个数或不同类型的参数,编译器就可以根据这一点判断出用new 关键字创建对象时,该调用哪个构造方法了。Java 会根据我们在括号中传递的参数,自动为我们选择相应的构造方法。Person p = new Person(参数列表),根据参数列表的不同去调用不同的构造方法。重载构造方法可以完成不同初始化的操作。

构造方法的一些细节

1:) 在Java的每个类里都至少有一个构造方法,如果程序员没有在一个类里定义构造方法,系统会自动为这个类产生一个默认的构造方法,这个默认构造方法没有参数,在其方法体中也没有任何代码,即什么也不做。一旦编程者为该类定义了构造方法,系统就不再提供默认的构造方法了。

2:)如果程序员定义的构造方法是有参数的,那创建对象时就必须传参,否则会报错。针对这种情况,我们只要自己定义构造方法时,都需要再带上一个无参数的构造方法,否则,就会经常碰到上面这样的错误。

3:)如果局部变量的名字与属性名一样,则采用就近原则

public Student(String name, String sex){
    name = name;//此时相当于把局部变量的值赋值给了局部变量,对象的name属性没有拿到值
    this.sex = sex;//如果局部变量的名字与属性名一样,可以用this.属性名 来区分属性和布局变量
}

this关键字

this的指向

代表本类的一个对象,谁调用就是谁

this关键字的主要应用

(1)this. 属性名 调用本类中的属性,也就是类中的成员变量,区分局部变量与属性;(this相当于是对象的名字)

(2)this调用本类中的其他方法,一般省略this, (方法都在同一个类中,可以直接调用);

(3)this调用本类中的其他构造方法,调用时要放在构造方法首行

public class Student {
	String name; // 定义一个成员变量name
	public void setName(String name) { // 定义一个参数(局部变量)name
        //这个this一定不能省略
		this.name = name; // 将局部变量的值传递给成员变量
	}
   
    public void fun(){
        //这个this可以省略,可以写成 setName(“张三”); 同类中的方法调用
		this.setName("张三"); //调用setName()的方法
	}
}
this(参数) 调用本类的其他构造方法

1:)只是方法的调用,不会创建对象(不要在构造方法里使用new 类名()来调用其他的构造方法!会再创建出对象)

2:)只能在构造方法中使用,且必须在第一行

public class Student { 
	public Student() { // 定义一个构造方法
		this("Hello");// 通过this()来调用另一个Student(String name)构造方法
        System.out.println("构造方法执行了");
	}

	public Student(String name) { // 定义一个带形式参数的构造方法
	}
}
这种方式来调用构造方法的话,有一个语法上的限制。一般来说,利用this关键字来调用构造方法,只有在无参数构造方法中第一句。否则的话,翻译的时候,就会有错误信息。这跟引用成员变量不同。如果引用成员变量的话,this关键字是没有位置上的限制的。

static关键字

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享

只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。

static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,**可以直接通过类名来访问,**访问语法为:

类名.静态方法名(参数列表…)

类名.静态变量名

用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块(用处非常大)。

静态变量(类变量)和实例变量

类成员变量分为两种,被static修饰的变量,叫静态变量或类变量;没有被static修饰的变量,叫实例变量

两者的区别

静态变量在内存中只有一个拷贝(节省内存),Java虚拟机(JVM)只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),也可以通过对象来访问(但是这是不推荐的)。

对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。所以一般在需要实现以下两个功能时使用静态变量

1).在对象之间共享值时(作为常量)
2).方便访问变量时

public class TestStatic1 {
	int a;  //a 是属性,是对象的成员变量,每一个对象都会有自己的属性
	static int b; //这个是类变量,所有的该类的对象都共享它
	
	public static void main(String[] args) {
		//创建本类的一个对象
		TestStatic1 t1 = new TestStatic1();
		t1.a = 10; //给属性赋值
		t1.b = 20;//给类变量赋值,也可以写成: TestStatic1.b=20;
		
		//创建本类的另外一个对象
		TestStatic1 t2 = new TestStatic1();
		t2.a = 5; 
		t2.b = 8;
		
		System.out.println("t1对象:t1.a="+t1.a);//10
		System.out.println("t1对象:t1.b="+t1.b);//8
		
		System.out.println("t2对象:t2.a="+t2.a);//5
		System.out.println("t2对象:t2.b="+t2.b);//8
		
	}
}

静态方法

静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员方法),只能访问所属类的静态成员变量和成员方法。

public class TestStatic2 {
	int a;
	static int b;
	public static void fun1(){
		System.out.println("这是TestStatic2类的静态方法fun1");
	}
	
	public static void fun2(){
	    //	a=10;// 不能直接访问a,因为static修饰的方法只能直接访问本类的静态的成员变量
		//fun3();//报错,不能直接访问fun3,因为static修饰的方法只能直接访问本类的静态方法
		b=10;//可以访问,因为b是静态的
		fun1();//可以访问
		System.out.println("这是TestStatic2类的静态方法fun2");
	}
	
	public void fun3(){
		System.out.println("这是TestStatic2类的非静态方法fun3");
	}
}
public class TestStatic3 {
	public static void main(String[] args) {
		//访问TestStatic2总的fun2方法,只需要使用类名.fun2()
		//因为fun2是静态方法
		TestStatic2.fun2();
		//调用TestStatic2非静态方法,只能使用对象名.方法名()来调用
		System.out.println("====================");
		TestStatic2 t1 = new TestStatic2();
		t1.fun3();
	}
}
调用静态属性和方法

对象.静态属性(方法)

类名:静态属性(方法) 推荐使用这个

使用场景

工具类、静态代码块

(不要随便定义静态资源)

静态资源的缺点

1.静态资源只能使用静态资源(例如静态方法里只能使用静态变量、调用静态方法)

  • 非静态方法的调用, 在其他类,main方法内调用: 先创建方法所在类对象,然后通过对象名.方法名() 来调用

  • 静态方法的调用: 在其他类,main方法内调用, 直接使用类名.静态方法名()

  • 静态方法优点: 调用简单

  • 静态方法的缺点: 无法使用非静态资源(实例属性,非静态方法, this,super),只能使用静态资源, 非静态方法调用非静态资源,也调用静态资源

  • 静态方法的缺点2: static修饰的, 不会被gc回收, 等到程序结束之后才回收

在使用类的静态方法时,我们要注意以下几点:
  1. 在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。

  2. 静态方法不能以任何方式引用this和super关键字(super 关键字在下一章讲解)。与上面的道理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生。

  3. main()方法是静态的,因此JVM 在执行main 方法时不创建main 方法所在的类的实例对象,因而在main()方法中,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在以后的例子中会多次碰到。

静态代码块

使用场景 做初始化操作, 做准备工作

一个类中可以使用不包含在任何方法体中的静态代码块(static block ),当类被载入内存时,所有的静态代码块被自动执行,且只被执行一次且在构造方法之前执行,静态块经常用来进行类属性的初始化,一个类可以写多个静态代码块, 执行顺序,从上往下。如下面的程序代码:

语法:

ststic{
    //静态代码块
}
public class TestStatic4 {
	//定义一个静态代码块
	static{
		System.out.println("这是一个静态代码块");
	}
	
	//构造方法
	public TestStatic4(){
		System.out.println("这是构造方法");
	}
	
	public static void main(String[] args) {
		TestStatic4 t1 = new TestStatic4();
		TestStatic4 t2 = new TestStatic4();
	}
}
//结果
这是一个静态方法
这是构造方法
这是构造方法

包 package

在Java中使用包来对类进行分类 ,在文件系统就是一个文件夹

包名:

一般是公司域名的反写 例如百度域名:www.baidu.com 百度项目的包名:com.baidu.[项目名].[模块名]

不能以关键字命名,否则会变成普通文件夹(图标有圆点的是包,没有就是普通文件夹)

同一个项目下可以存在相同名称的类,但是这两个类不能位于同一个包中

import导入

不需要导包的情况

1:)当一个类想要使用另一个类,如果这两个类在同一个包中,可以直接使用,不需要导包

2:)如果想要使用的类位于java.lang包中, JVM虚拟机会自动导入(例如String、System 等等

什么时候需要导包?

如果两个类不在同一个包中,且被使用的类也不属于java.lang包,则需要用import关键字导入,且位于class外面

import 包名.类名//语法
import java.utils.Scanner;//导入java.utils包中的Scanner类
import java.utils.*//导入java.utils包中所有的类

静态导入, 把某个类的所有的静态方法导入‘

封装

封装的概念

封装是 JAVA 面向对象的特点的表现,封装是一种信息隐蔽技术。它有两个含义:即把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位;以及尽可能隐藏对象的内部结构。也就是说,如果我们使用了封装技术的话,别人就只能用我们做出来的东西而看不见我们做的这个东西的内部结构了。提高了安全性和复用性

封装的功能:
  • 隐藏对象的实现细节,保护安全
  • 封装迫使用户通过指定方法访问数据能保护对象的数据不被误修改
  • 使代码更好维护, 使对象的重用变得更简单

Java中封装的实现

封装的步骤

1:)把属性的访问修饰符设置为private(修饰的资源只能在本类中使用)

2:)给属性提供public 的get/set方法 IDEA快速生成 alt+insert

封装如何实现对数据的控制?

例如限制用户的年龄只能在16-40岁,可以将age属性设置为private,在setAge(int age)方法中放入限制age的逻辑代码(例如if语句)

Java通过三个关键字来控制对象的成员的外部可见性 public, private, protected。
  • public: 该成员外部可见,即该成员为接口的一部分
  • private: 该成员外部不可见,只能用于内部使用,无法从外部访问。
  • protected:后面介绍

Person类:

public class Person {
	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;
	}
public void showInfo(){
		this.setName("无名氏");
		age = 21;
	}
}

TestPerson类:

public class TestPerson1 {
	public static void main(String[] args) {
		Person p1 = new Person();
		//p1.setName()可以访问,因为setName是public
		p1.setName("张三");
		//p1.age不能访问,因为age是private的
		//p1.age=21;		System.out.println(p1.getName());
	}
}

程序分析:

​ 一个类的内部方法并不受封装的影响。Person的内部方法showInfo()可以调用任意成员,即使是设置为private的age. 外部方法只能调用public成员。当我们在Person外部时,比如TestPerson类中,我们只能调用Person类中规定为public的成员,而不能调用规定为private的成员。

通过封装,Person类就只保留了下面几个方法作为被其他类调用.

  • getName()
  • setName()
  • getAge()
  • setAge()
  • showInfo()

如果我们从TestPerson类的main中强行调用age:p1.age=21将会报错

在Java的通常规范中,表达状态的数据成员(比如age,name)要设置成private。对数据成员的修改要通过接口提供的方法进行(比如getAge()和setAge())。这个规范起到了保护数据的作用。用户不能直接修改数据,必须通过相应的方法才能读取和写入数据。类的设计者可以在接口方法中加入数据的使用规范。

封装的作用

1:)提高易用性(使用简单),编写一个类,内部很复杂,将复杂的代码封装起来(例如用private修饰),暴露出几个方法。

2:)提高安全性,将某些方法和属性屏蔽起来,禁止用户访问,从而提高类的安全性(保护数据)

3:)把重复的代码抽取出来,使用方法,或者类来封装,从而实现代码的重用

继承

继承的概念

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例和方法,或子类从父类继承方法,使得子类具有父类相同的行为。父类更通用,子类更具体,子类会具有父类的一般特性也会具有自身的特性。注意:构造方法不能继承且子类不能访问继承的private资源

作用

1:)实现代码的重用, 基于类层次的代码重用

2:) 把多个子类中公共的代码,抽取出来, 放到父类中, 子类继承父类, 这个公共代码,被子类继承,从而实现代码的重用

继承的使用步骤

1:)把子类公共的代码抽取出来,形成父类

2:)使用关键字extends让子类继承父类

类的继承格式
class 子类 extends 父类 { }

注意:

在 java 中只允许单继承,而不允许多重继承,也就是说一个子类只能有一 个父类,但是 java 中却允许多层继承. 比如类 B 继承了类 A,而类 C 又继承了类 B,也就是说 类 B 是类 A 的子类,而类 C 则是类 A 的孙子类。我们java的所有类都有一个祖先类,就是我们的Object类.如果一个类没有显示写继承哪个类,默认继承java.lang.Object

子类对象的实例化过程(重要)

在创建一个子类的对象时会默认先去调用父类中的无参构造方法,之后再 调用本类中的相应构造方法。

public 子类(){
  super();//默认调用父类中的无参构造方法,默认省略
  super(参数列表);//调用父类中的有参构造方法,此时不会执行父类中的无参构造方法
}

1:)第一步是先初始化父类的属性**(面试题)**

2:)调用父类的构造方法

3:) 初始化子类的属性

4:)执行子类的构造方法

继承条件下构造方法的调用规则

  1. 如果子类的构造方法中没有通过super显式调用父类的有参构造方法,也没有通过this显式调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法。在这种情况下,写不写“super();”语句,效果是一样的。
  2. 如果子类的构造方法中通过super显式调用父类的有参构造方法,那将执行父类相应构造方法,而不执行父类无参构造方法。
  3. 如果子类的构造方法中通过this显式调用自身的其他构造方法,在相应构造方法中应用以上两条规则。
  4. 特别注意的是,如果存在多级继承关系,在创建一个子类对象时,以上规则会多次向更高一级父类应用,一直到执行顶级父类Object类的无参构造方法为止。
  5. 如果父类声明了一个有参的构造方法,但是没有声明无参的构造方法,则创建子类时会报错(提示无法找到 父类),因为子类对象找不到父类中的无参构造方法,所以程序出现了错误,只要在 Person 类中增加一个什么都不做的 构造方法,就这一问题就可以解决了

super 关键字

super表示的是父类的对象,this表示的是本类的对象

super主要的功能是:子类用来调用父类中的属性或方法。

注意:

用 super 调用父类中的构造方法,只能放在程序的第一行。

super 关键字不仅可以调用父类中的构造方法,也可以调用父类中的属性或方法,

super.父类中的属性 ; 一般不这样使用,因为属性一般用private修饰(属性私有化)

super.父类中的方法() ;

super()和this()的关系

super([参数]):调用父类的构造方法

this([参数]):调用本类的构造方法

super()的注意事项

1:)只能在子类的构造方法中调用且必须在第一行(所以super()与this()不能同时存在,因为他俩都要在构造方法的首行)

2:)如果子类构造方法没有写super(), jvm会自动添加super(), 手动编写super()调用父类构造方法, jvm不会添加`super()

总结:

  • 子类拥有父类非private的属性,方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系)。

访问修饰符

Java面向对象的基本思想之一是封装细节并且公开接口。Java语言采用访问控制修饰符来控制类及类的方法和变量的访问权限,从而向使用者暴露接口,但隐藏实现细节。访问控制分为四种级别:

(1)public: 用public修饰的类、类属变量及方法,包内及包外的任何类(包括子类和普通类)均可以访问,(同项目下的类都可以访问);

(2)protected: 用protected修饰的类、类属变量及方法,包内的任何类及包外那些继承了该类的子类才能访问,protected重点突出继承(同一个包或者继承的子包可以访问);

(3)default: 如果一个类、类属变量及方法没有用任何修饰符(即没有用public、protected及private中任何一种修饰),则其访问权限为default(默认访问权限)。默认访问权限的类、类属变量及方法,包内的任何类(包括继承了此类的子类)都可以访问它,而对于包外的任何类都不能访问它(包括包外继承了此类的子类)。default重点突出包;

(4)private: 用private修饰的类、类属变量及方法,只有本类可以访问,而包内包外的任何类均不能访问它。

实际开发中通常用public、private
public: 暴露给调用者使用
private: 不让调用者使用,本类内部使用
访问级别 访问控制修饰符 同类 同包不同子类 同包子类 不同包不是子类 不同包子类
公开 public
受保护 protected
默认 没有访问控制修饰符 zee
私有 private

注意:

protected修饰符的修饰的成员变量和方法也称为受保护的成员变量和方法, 受保护的成员变量和方法可以在本类或同一个包中的其它类(包括子类)中通过类的实例进行访问,也可以被同一个包中的类或不同包中的类继承,但是不能在不同包中的其它类(包括子类)中通过类的实例进行访问。

方法的重写(OverWrite)

子类继承了父类,那么子类的对象理应可以使用父类中的非private方法,如果子类想实现与父类不一样的效果怎么办呢?此时子类可以重写父类中的方法,当子类的对象再调用这个方法时,就不再是执行父类中写的那个了,而是执行在子类中重写的那个方法,**即保持方法的定义不变,但方法内部实现同父类中不同,**很好理解:如果子类重写了父类中的方法,调用的就是子类中的实现,否则就调用父类中的方法

重写规则/特征

1:)子类重写父类或父辈类中的方法,父类方法的参数列表必须完全与被子类重写的方法的参数列表相同

2:)父类的返回类型必须与被子类重写的方法返回类型相同,

3:) Java中规定,被子类重写的方法不能拥有比父类方法更加严格的访问权限

如果子类对象不仅想调用自己重写的方法又想调用父类的那个被重写的方法怎么办?——使用super.方法()
public void showInfo(){
    super.showInfo();//调用父类那个被重写的方法
    System.out.print("子类重写父类的方法")
}
可以在子类重写的方法上添加注解 @override,如果方法名出错会被检测出来

快捷键 alt+insert ctrl+o

面试题:方法重载与方法重写的区别

抽象类

如果父类中的某个方法,对于他的不同子类来说有着不一样的实现效果,(也就是说,父类不用实现这个方法,这个方法交给不同的子类自己去重写),此时父类的这个方法不用去写方法的实现,只需要声明这个方法让子类去继承就 可以了,但是如果这样,程序会编程出错,所以就得加一个关键字: abstract, 这种只需要声明,不需要实现方法体的方法,我们叫做抽象方法.但是如果一个类中包含了抽象方法,那么该类也必须声明为抽象类,也就是说:含有抽象方法的类叫做抽象类, 声明这个类时也需要加adstract关键字.

抽象类也可以像普通类一样,有构造方法、一般方法、属性,更重要的是还可以有一些抽象方法,留给子类去实现.

抽象类的规则

  • 抽象类可以包含属性和普通方法(非抽象方法)
  • 抽象类和抽象方法都必须用 abstract 关键字来修饰,且访问修饰符不能是private。
  • 抽象方法不能使用static、final修饰
  • 抽象类不能被实例化,不能用 new 关键字去创建抽象类的对象,但是可以创建一个继承了抽象类的子类的对象,也就是说,抽象类不能实例化,但是抽象类的子类可以被实例化,前提是这个子类重写了父类中的所有抽象方法。
  • 抽象方法只需声明,不需实现。
  • 含有抽象方法的类必须被声明为抽象类,抽象类的子类必须复写所有的抽象方法后才能被实例化否则这个子类还是个抽象类。
一个抽象类不一定包含抽象方法,但是抽象方法一定位于抽象类/接口

抽象方法的细节

1:)访问修饰符不能是private

2:)抽象方法不能使用static、final修饰**

final关键字

final意为“最终的”,在 Java 中声明类、属性和方法时,可使用关键字 final 来修饰。

1、 final 标记的类不能被继承

2、 final 标记的方法不能被子类复写

3、 final 标记的变量(成员变量或局部变量)即为常量只能赋值一次,而且只能在声明的时候就赋值。

final int a;//报错
final int a = 0;//只能赋值一次,不能修改值,值相同也不行,
public void fun(){
    a = 0;//报错,值相同也不能赋值,只能赋值一次
}

多态

通过一个父类引用不同的子类

抽象类也可以像普通类一样,有构造方法、一般方法、属性,更重要的是还可以有一些抽象方法,留给子类去实现.

抽象类的规则

  • 抽象类可以包含属性和普通方法(非抽象方法)
  • 抽象类和抽象方法都必须用 abstract 关键字来修饰,且访问修饰符不能是private。
  • 抽象方法不能使用static、final修饰
  • 抽象类不能被实例化,不能用 new 关键字去创建抽象类的对象,但是可以创建一个继承了抽象类的子类的对象,也就是说,抽象类不能实例化,但是抽象类的子类可以被实例化,前提是这个子类重写了父类中的所有抽象方法。
  • 抽象方法只需声明,不需实现。
  • 含有抽象方法的类必须被声明为抽象类,抽象类的子类必须复写所有的抽象方法后才能被实例化否则这个子类还是个抽象类。
一个抽象类不一定包含抽象方法,但是抽象方法一定位于抽象类/接口

抽象方法的细节

1:)访问修饰符不能是private

2:)抽象方法不能使用static、final修饰**

final关键字

final意为“最终的”,在 Java 中声明类、属性和方法时,可使用关键字 final 来修饰。

1、 final 标记的类不能被继承

2、 final 标记的方法不能被子类复写

3、 final 标记的变量(成员变量或局部变量)即为常量只能赋值一次,而且只能在声明的时候就赋值。

final int a;//报错
final int a = 0;//只能赋值一次,不能修改值,值相同也不行,
public void fun(){
    a = 0;//报错,值相同也不能赋值,只能赋值一次
}

多态

通过一个父类引用不同的子类

当新建一个子类时,只需要该子类继承父类,并且实现父类中的抽象方法即可而不需要去修改别的类

你可能感兴趣的:(java,c#,开发语言)