Java学习笔记——面向对象编程(OOP)

面向对象编程(OOP) Object Oriented Programming


面向对象的特点:封装 继承 多态 (抽象)


介绍

什么是类
 具有相同特点(属性)和行为(动作)的集合的总称.
 人类
 植物类
 手机类
什么是对象
 是某一类的具体体现 实例
 将类的抽象概念具体化.
 人类的对象: 张三,特朗普,…
  植物类的对象 : 路边的梧桐,杨树
  手机类的对象 : 正在使用的手机
什么是属性
 是一类事物的特点/特征.
 人类的属性/特征 : 肤色,年龄,身高,体重…
 植物类的属性 : 树干,树叶,树根,花,果实
 手机的属性 : 价格,重量,颜色,形状
什么是方法
 一类事物都可以进行的动作/行为.
 人类的动作 : 吃饭睡觉打豆豆
 植物的动作 : 开花,结果,光合作用
 手机的动作 : 打电话,发短信


以学生类为例


编写类

Student.java文件代表学生类
 类中有属性和方法
学生类:
 属性 : 姓名 年龄 学号 学校…
 方法 : 学习 吃饭 睡觉

属性的写法:
  [访问修饰符] 数据类型 变量名;
  []内的代码,可写可不写

[访问修饰符] 返回值类型 方法名([参数1],[参数2],…){
  方法内的执行语句;
   …
}
访问修饰符 : 控制访问权限
返回值类型 : 该方法执行后返回的结果的数据类型(基本数据类型/引用数据类型 )
      void : 空,方法执行后不返回任何数据
      …
  如果方法需要返回数据,
    1) 那就需要在返回值类型处写上返回数据的数据类型
    2) 在方法体的最后使用 return 值;的格式将值明确显示返回.
方法名 : 见名知意,驼峰原则
() 参数列表 :

  1. 形式参数 : 该方法执行可能用到的数据
  2. 形式参数的写法: 数据类型 变量名;
  3. 列表内可以写多个参数,或者不写
  4. 当方法参数列表有参数时,在调用时(让方法执行时)就必须给方法的参数赋值

{} 方法体
执行语句 : 该方法真正的功能体现

package com.zhiyou100.oop;

public class Student {
	
	public String name;
	public int age;
	public String stuNo;
	String schoolName;
	
	public String study(String book,String pen) {
		System.out.println("在学习"+book);
		String name = "张三";
//		return "李四";
		return name;
	}
	
	void eat() {
		System.out.println("吃");
	}
	
	void sleep () {
		System.out.println("睡觉");
	}
	
}

对象的创建使用

通过类 创建对象 <==> 实例化
类名 对象名 = new 类名();
数据类型 变量名 = 值;
对象属性取值:
 数据类型 变量名 = 对象名.属性名;

对象属性赋值:
 对象名.属性名 = 值;

调用对象的方法

  1. 方法有参数,调用时必须传入实参;实参与形参的个数,顺序,数据类型要保持
  2. 方法没有参数,不能给参数
  3. 方法无返回值,一定不能接收返回值
  4. 方法有返回值,可以接收,也可以不接收
     A : 无返回值
       A1 无返回值无参
         对象名.方法名();
       A2 无返回值有参数
         对象名.方法名(值1,值2,…);
      B : 有返回值
       B1 有返回值无参
         [数据类型 变量名 = ]对象名.方法名();
       B2 有返回值有参数
         [数据类型 变量名 = ]对象名.方法名(值1,值2,…);

扩展:
一个类可以创建多个对象,并且每个对象多有自己的属性和方法

package com.zhiyou100.oop;

public class TestOOP {

	public static void main(String[] args) {
	
		// 创建对象
		Student stu1 = new Student();
		System.out.println(stu1);
		// 获得属性值 
		String name = stu1.name;
		int age = stu1.age;
		String stuNo = stu1.stuNo;
		String schoolName = stu1.schoolName;
		System.out.println("name = "+name);
		System.out.println("age = "+age);
		System.out.println("stuNo = "+stuNo);
		System.out.println("schoolName = "+schoolName);
		// 属性赋值
		stu1.name = "张三";
		stu1.age = 18;
		stu1.schoolName = "北京大学";
		stu1.stuNo = "100001";
		System.out.println("name = "+stu1.name);
		System.out.println("age = "+stu1.age);
		System.out.println("stuNo = "+stu1.stuNo);
		System.out.println("schoolName = "+stu1.schoolName);
		System.out.println("----------分割线---------");
		// A1 无返回值无参
		stu1.eat();
		// A2 无返回值有参数
		stu1.sleep("地");
		// B1 有返回值无参
		String result1 = stu1.playGame();
		System.out.println("结果 : "+result1);
		// B2 有返回值有参数
		String result2 = stu1.study("<java从入门到精通>", "黑笔");
		System.out.println("谁在学习 ? : " + result2);
		
	}
	
}

对象在内存的图示

在这里插入图片描述

两个引用指向一个对象

public class TestOOP3 {

	public static void main(String[] args) {
		/*
		 * 两个引用指向一个对象
		 * s1 是对象名,也是变量,也可以叫做引用
		 * s1引用的是内存中堆中的对象的地址值
		 * Student s2 = s1;
		 * 将引用赋值给s2.
		 * s1 和 s2 操作的是内存中的同一个对象
		 */
		Student s1 = new Student();
		Student s2 = s1;
		s1.name = "刘备";
		System.out.println(s2.name);
	};

}

在这里插入图片描述
方法的参数列表是类名时,该如何调用 ?
调用时,传入该类型的对象

完整的内存图

在这里插入图片描述

局部变量和成员变量

不同点
成员变量: 成员属性/全局变量/全局属性
  位置 : 类中,方法外
  在内存的位置 : 在堆内存
  生命周期 : 随着对象创建在堆中出现,随着对象被垃圾回收(GC)而消失
  初始值 : 随着创建对象,赋默认值
局部变量:
 位置: 方法参数列表中,或者方法体内
 在内存的位置 : 在栈内存
 生命周期 : 随着方法进栈而出现,方法执行完弹栈而消失
 初始值 : 在使用前必须给定值.
使用时的注意事项
当方法局部变量与成员变量重名时,
方法内使用时 “就近原则”,默认使用方法自己的局部变量
如果重名时,想要继续使用成员变量.要使用this指代
this.属性 指代成员变量
this就是当前调用该方法的对象

访问控制符修饰类

  1. 访问修饰符都可以修饰属性/成员变量
  2. 访问修饰符都可以修饰方法
  3. 访问修饰符又叫访问控制符/权限控制符
  4. 作用就是: 控制被修饰的属性或者方法在被别处(包括当前类或者其他类中)的访问权限.
    在这里插入图片描述

封装

封装的概念

把客观事物封装成抽象的类,并且类可以把自己的属性和方法只让可信的类或者对象进行操作,对不可信的类或者对象隐藏,这样的过程叫做封装。
封装的分类

对属性的封装

将属性设置为private(私有),限制其只能在类的内部使用;提供set、get方法,set方法给属性赋值,get方法获得属性值。
setter getter 的方法名写法:setXxx、getXxx,Xxx 是类的属性首字母大写,访问修饰符不可以是private。

对方法的封装

对于方法的封装,将外部可以访问方法设置为public,将外部不能访问的方法设置为private
构造方法
构造方法/构造函数/构造器/constructor
作用 :
 创建对象,属性赋值
 new 构造方法();
语法格式 :
 访问修饰符 类名() {
 }
特点:

  1. 任何一个类中都默认隐式存在无参构造方法
  2. 构造方法没有返回值类型,连void都没有
  3. 构造方法的方法名是当前类的类名,首字母大写
  4. 在程序中显示写出任意一个构造方法.那么隐式的不再提供.

继承

一个新类从现有的类派生,这样的过程叫做继承
那么在继承的过程中,新类被称为子类,现有的类被称为父类,子类将会继承父类的属性和行为。
继承的语法
[修饰符] class 子类类名 extends 父类类名{子类类体部分}
子类的扩展
子类除了可以拥有父类非私有的属性和方法外,也可以扩展自己的属性和方法
使用

  1. Java中的继承是单继承,也就是一个类只能有一个父类。
  2. 如果一个类没有显式的继承某一个类,那么它有一个默认的父类是java.lang.Object类
  3. Java继承了父类非私有的成员变量和方法,但是请注意:子类是无法继承父类的构造方法的
  4. 子类可以使用父类的属性和方法,也可以使用租父类属性和方法 --> 多层次继承

在继承中成员变量的访问
1 当子类中没有该成员变量时,那么调用的就是父类的成员变量
2 当子类与父类有重名的成员变量时,默认访问的是子类自己的属性
但是一般情况时,子类不会有与父类重名的属性,因为继承就是为了使用父类的属性和方法

在继承中成员方法的访问
1 当子类中没有该方法时,那么调用的就是父类的方法
2 当子类有与父类重名的方法时 ——》方法的重写(@Override)
当子类重写了父类方法后,在调用时,调用的就是子类自己的方法

在继承中构造方法

  1. 构造方法不能继承,也不能被重写.更不能被对象调用.
  2. 在继承中,子类的构造方法会在构造方法第一行隐式调用父类无参构造. super();
  3. 如果现式写出调用父类构造方法的代码,必须写在第一行.
  4. 默认是调用父类无参的,也可以使用super(参数)调用父类有参数的构造方法
    在这里插入图片描述

多态

概念

什么是多态
 多态顾名思义即为多种形态的意思
Java中多态的含义
 发送消息给某个对象,让这个对象自行决定采用哪种行为响应这个消息
 子类对象的引用赋值给父类引用变量来实现动态的方法调用
 属性没有多态性,方法有多态性
Java中形成多态的前提
 继承
 重写
 父类引用指向子类对象

父类无法调用子类特有的方法
想要调用子类特有的方法,需要由子类自己的对象调用
向下转型: 父类转成子类
父类由哪个子类向上转型而成,那就只能向下转型成哪个子类. 而不是随便转变成任意子类.
a instanceof Dog: a变量如果是Dog类的对象,就返回true

抽象

1 抽象方法没有方法体
2 抽象方法还需要由abstract修饰
3 抽象方法必须定义在抽象类中
4 抽象类需要abstract修饰
5 抽象类不一定有抽象方法
6 抽象类也可以拥有正常的方法
7 属性不能被abstract修饰
8 抽象类可以有构造方法,但是不能创建对象
9 抽象类还是类
10 抽象类不能创建对象
11但是可以使用多态特性

继承抽象类
子类继承抽象类,必须重写父类的全部抽象方法,否则,就必须将子类也定义成抽象类

接口

接口相当于一种规范,约束

含义

各个小组的开发工作是并行的。在很多时候,对于不同小组的程序员来说,清楚地说明各自的软件如何相互作用,并就此达成统一“约定”是很重要的。这种情况下,每一小组都可以在对其他小组怎么编写代码一无所知的情况下,就能编写自己的代码,并且各自小组编写的代码能很好的协同工作。接口就是这样的“约定”。

在Java中接口不仅仅是程序开发过程中“约定”,更是更加抽象化的抽象类.
接口就是让你知道它在做什么,而无需知道它们怎么做;接口更深层的理解是:使定义(规范和约束)和实现(具体的代码逻辑)分离,它是沟通(交互)的中介物(具体实现)的抽象化。
接口即是设计:在设计层面,接口可以避免我们陷入对细节的过多思考,可以让我们站在一个更高的视角对系统做更好的评估,比如系统的交互设计是否合理,功能是否缺失,是否具备可行性,是否过于复杂等等。接口即是约定:在编码层面,接口可以明确的告诉开发人员如何使用(接口的语义,需要什么作为输入,会有什么输出),而开发人员只需要根据这些约定去实现具体的功能代码即可。统一类的共同行为:接口用来统一类的共通行为,当不同的类需要进行信息共享时,是不需要特别去创建类间的关系。举例来说,一个人(Human)及一只鹦鹉(Parrot)都会吹口哨(whistle),然而 Human 及 Parrot 不应该为 Whistler 的子类,最好的做法是令他们为 Animal 的子类,而他们可以使用 Whistler 的接口进行沟通。

接口是一种比抽象类更加抽象的“类”。这里给“类”加引号是我找不到更好的词来表示,但是我们要明确一点就是,接口本身就不是类.

特点

1 接口文件是interface修饰,接口不是类
2 接口中的成员变量默认都被public final static
3 接口中不存在正常带方法体的方法,默认都是抽象方法,都默认被public abstract修饰在jdk8后可以使用default
4 接口中没有构造方法,不能创建对象

实现

  • 类 实现 接口,可以多实现,多个接口用,隔开
  • 类 继承 类,是单继承
  • 接口 继承 接口,且可以多继承,多个,接口逗号隔开

  • 类实现接口,要重写全部的抽象方法
  • 如果不重写或者没有全部重写,那么子类要定义成抽象类
    类可以在实现接口的同时,继承其他类–>写法是先 extends 后 implements




static关键字的作用与用法

static 在可用来修饰属性、方法。

常用方式:
static:main方法固定搭配(规定)

public static void main(String[] args){}

static特点

  1. 可以修饰属性,方法,在内存中只有一份
  2. 修饰的属性叫做类属性 该属性属于当前字节码文件(xx.class),被当前类创建出的所有对象共享,同理还有类方法
  3. 凡是被static修饰的属性和方法,会随着类加载而初始化
     类属性比对象属性先在内存出现,类属性可以不通过对象调用
     类名.静态属性;
     类名.静态方法();

注意:

  1. 静态方法只能调用静态的属性和方法 --> 静态只能调用静态
  2. 非静态方法既可以非静态属性和方法,也可以调用静态的属性和方法–> 非静态什么都可以调用
  3. 静态方法中不能使用this

说明:

  1. static变量:按照是否静态的对类成员变量进行分类:一种是被static修饰的变量,叫静态变量(类变量);另一种是没有被static修饰的变量,叫实例变量。
     区别:
      a、对于静态变量在内存中只会一次拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中优先加载完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
      b、对于实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。
  2. static代码块:static代码块是类加载时,初始化自动执行的,其优先级仅次于静态变量。如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。
  3. static方法:static方法可以直接通过类名调用,任何的实例也都可以调用,因此static方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(也就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。tatic方法只能访问static的变量和方法,因为非static的变量和方法是需要创建一个对象实例才能访问的,而static的变量/方法不需要创建任何对象。

提示:
static的数据或方法,属于整个类的而不是属于某个对象的,是不会和类的任何对象实例联系到一起。所以子类和父类之间可以存在同名的static方法名,这里不涉及重载。所以不能把任何方法体内的变量声明为static。

this与super

在这里插入图片描述

重写(Override)与重载(Override)

重写(Override)

重写是子类对父类的允许访问的方法的实现过程进行重新编写!返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。

方法重写的规则

  1. 参数列表必须完全与被重写方法的相同; 返回类型必须完全与被重写方法的返回类型相同;
  2. 访问权限不能比父类中被重写的方法的访问权限更高。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
  3. 父类的成员方法只能被它的子类重写。 声明为final的方法不能被重写。 声明为static的方法不能被重写,但是能够被再次声明。
  4. 如果一个方法不能被继承,那么该方法不能被重写。
  5. 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
  6. 子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。
  7. 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  8. 构造方法不能被重写。 如果不能继承一个方法,则不能重写这个方法。

重载(Overload)

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
只能重载构造函数

方法重载的规则

  1. 被重载的方法必须改变参数列表;
  2. 被重载的方法可以改变返回类型;
  3. 被重载的方法可以改变访问修饰符;
  4. 被重载的方法可以声明新的或更广的检查异常;
  5. 方法能够在同一个类中或者在一个子类中被重载
    在这里插入图片描述

final关键字:

	 * 1 修饰变量
	 * 	  变量不再是变量而是常量.必须赋初始值且值不可再改变.
	 * 2 修饰方法
	 * 	 final修饰的方法不能被重写
	 * 3 修饰类
	 * 	finale修饰类,类不能被继承
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值