Java——面向对象
面向对象
0、零基础教程目录
1、课程框架
1、目录
2、主体框架
-
1、面向对象的理解
-
2、类和对象
-
3、类的内部成员
- 3.1 属性
- 3.2 方法
- 3.3 构造器
- 3.4 部分关键字
2、面向过程 (POP ) 与 面向对象 OOP
- 二者 都是一种思想,面向对象是相对于面向过程而言的。面向过程, 强调的是 功能 行为,以函数为最小单位,考虑怎么做 。面向对象,将功能封装进对象, 强调具备了功能 的 对象,以类 对象为最小单位,考虑谁来做。
- 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
- 面向对象的三大特征
- 封装 (Encapsulation)
- 继承(Inheritance)
- 多态(Polymorphism)
实例对比
3、类和对象
1、定义
类 (Class 和 对象 (Object 是面向对象的核心概念。
- 类 是对 一类事物的描述 ,是 抽象的 、概念上的定义
- 对象 是 实际存在 的该类事物的每个个体,因而 也称为 实例 。
- 万事万物皆对象
2、组成元素
现实生物世界中的细胞又是 由什么构成的 呢?细胞核、细胞质、 … 那么Java 中用类 class 来描述事物也 是 如此。常见的类的成员有:
- 属 性 :对应类中的成员变量
- 方法:对应类中的成员方法
Field =属性 = 成员变量, Method = ( 成员) 方法 = 函数
总体使用实例说明:
使用方式:类的语法格式
创建Java 自定义类:
步骤:
-
1.定义类(考虑修饰符、类名)
-
2.编写类的属性 考虑修饰符、属性 类型、属性名 、 初始化值)
-
3.编写类的方法 考虑修饰符、返回 值类型、方法名、形参等)
修饰符 class 类名{
属性声明;
方法声明;
}
说明: 修饰符 public :类可以被任意访问
类的正文要用{ }括起来
举例:
public class Person{
private int age ; //声明私有变量 age
public void showAge (int i ) { //声明方法 showAge ()
age = i
}
}
3.1、对象的创建和使用
使用方式
- 创建对象语法:
类名 对象名 = new 类名()
- 使用“
对象名.对象成员
”的方式访问对象成员(包括属性和 方法)
举例说明
public class Animal {
public int legs;
public void eat(){
System.out.println(“Eating”)
}
public void move(){
System.out.println("Move");
}
}
public class Zoo{
public static void main(String args[]){
//创建对象
Animal xb =new Animal();
xb.legs = 4;;// 访问属性
System.out.println(xb.legs);
xb.eat;//访问方法
xb.move;//访问方法
}
}
注意:
类的访问机制:
- 1、
在一个类中的访问机制
: 类中的方法可以直接访问类中的成员变量 。
另外: static 方法访问非 static 编译不通过 。
- 2、
在不同类中的访问机制:
先创建要访问类的对象 再用对象访问类中定义的成员 。
对象的创建和使用:匿名对象
我们 也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。
如: new Person().shout();
使用 情况
- 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
- 我们经常将匿名对象作为实参传递给一个 方法 调用。
package com.itguigu.java;
/*
* 一、理解“万事万物皆对象”
* 1、在Java语言范畴中,我们都将功能、结构等封装到类中,通过类到实例化,来调用具体的功能结构。
* 2、涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。
*
* 二、内存解析的说明
* 1、引用类型的变量,只可能存储两类值:null或地址值(含变量的类型)
*
* 三、匿名对象的使用
* 1、理解:我们创建的对象,没有显式的赋给一个变量名,即为匿名对象。
* 2、特征:匿名对象只能调用一次。
* 3、使用:
*/
public class InstanceTest {
public static void main(String[] args) {
Phone p = new Phone();
System.out.println(p);
p.sendEmail();
p.playGame();
//匿名对象
// new Phone().sendEmail();
// new Phone().playGame();
new Phone().price = 1999;
new Phone().showPrice();
//**********************************
PhoneMall mall = new PhoneMall();
mall.show(new Phone());
}
}
class PhoneMall{
public void show(Phone phone) {
phone.sendEmail();
phone.playGame();
}
}
class Phone{
double price; //价格
public void sendEmail() {
System.out.println("发送邮件");
}
public void playGame() {
System.out.println("玩游戏");
}
public void showPrice() {
System.out.println("手机价格为:"+price);
}
}
对象的产生:内存状态说明
class Person{
int age;
void shout(){
System.out.println(“oh,my god! I am ” + age)”);
}
}
class PersonTest{
public static void main(String[]args ) { 程序运行的内存布局如下图
Person p1 = new Person();
Person p2 =new Person();
p1.age = 30;
p1.shout();
p2.shout();
}
}
3.1.1、对象的创建和使用:内存解析
- 1、
堆 (Heap)
此内存区域的唯一目的就是存放对象实例
几乎所有的对象实例都在这里分配内存 。 这一点在Java
虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配 。 - 2、
栈 (Stack )
是指虚拟机栈 。 虚拟机栈用于存储 局部变量
等 。局部变量表存放了编译期可知长度的各种基本数据类型boolean 、 byte 、char 、 short 、 int 、 float 、 long 、double 、 对象引用reference 类型它不等同于对象本身 是对象在堆内存的首地址 。 方法执行完 自动释放 。 - 3、
方法区 (Method Area)
用于 存储已被虚拟机加载的类信息 、 常量 、 静态变量 、 即时编译器编译后的代码
等数据 。
对象的内存解析举例
3.2、类的成员之一:属性
成员变量(属性)和局部变量的区别?
成员变量vs 局部变量的内存位置
对象属性的默认初始化赋值
当一个对象被创建时,会对其中各种类型的 成员变量 自动进行初始化赋值。除了基本数据类型之外的变量类型都是引用类型,如上面的 Person 及前面讲过的数组。
3.3、类的成员之二: 方 法 (method)
定义;
什么是方法(method 、函数):
-
1、方法 是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
-
2、将功能封装为方法的目的是,可以实现代码重用,简化代码
-
3、Java 里的方法不能独立存在,所有的方法必须定义在类 里。
实例
public class Person{
private int age;
public int getAge()
{ 声明方法 getAge()
return age;
}
public void setAge(int i)// 声明方法 setAge
{
age = i; 将参数 i 的值赋给类的成员变量 age
}
}
使用方法
3.3.1、四种使用形式
注 意:
-
1、方法被调用一次,就会执行一次
-
2、没有 具体返回值的情况,返回值类型用关键字 void 表示 ,那么方法体中可以不必使用 return 语句。如果使用,仅用来结束方法。
-
3、定义方法时,方法的结果应该返回给调用者,交由调用者 处理 。
-
4、方法中只能 调用 方法或属性, 不可以在方法内部定义方法。
3.3.2、方法调用的过程分析
3.3.3、再谈方法1.0 :方法的重载 (overload)
定义
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
特点
与返回值类型无关,只看参数列表,且参数列表必须不同。参数个数或参数类型 。调用时, 根据方法参数列表的不同来区别。
重载示例:
package com.itguigu.java;
/*
* 方法的重载(overload)
* 1、定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
* "两同一不同":同一个类、相同方法
* 参数列表不同:参数个数不同、参数类型不同
* 2.举例
* Arrays中的sort、binarySearch
*
* 3.判断是否是重载
* 跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系。
*
* 4.在通过对象调用方法时,如何确定某一个指定的方法。
* 方法名-->参数列表
*/
public class OverLoadTest {
public static void main(String[] args) {
OverLoadTest test = new OverLoadTest();
test.getSum("1", 2);
}
public void getSum(int i, int j) {
System.out.println(1);
}
public void getSum(double d1, double d2) {
System.out.println(2);
}
public void getSum(String s, int i) {
System.out.println(3);
}
public void getSum(int i, String s) {
System.out.println(4);
}
// public int getSum(int i, int j) {
// return 0;
// }
// public void getSum(int m, int n) {
//
// }
// private void getSum(int i, int j) {
//
// }
}
3.3.4、再谈方法 2.0 :可变个数的形参
JavaSE 5.0中 提供了 Varargs( variable number of arguments 机制 ,允许直接定义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。
//JDK 5.0
以前: 采用 数组形参来 定义 方法,传入多个同一类型变量
public static void test(int a ,String[] books);
//JDK5.0
采用 可变 个数形参来 定义 方法,传入多个同一类型变量
public static void test(int a ,String…books);
使用说明:
-
1、声明格式: 方法名 参数的类型名 参数名
-
2.可变 参数:方法参数部分指定类型的参数个数是可变 多 个: 0 个, 1 个或多个
-
3.可变 个数形参的方法与同名的方法之间,彼此构成重载
-
4.可变 参数方法的使用与方法参数部分使用数组是一致的
-
5.方法 的参数部分有可变形参,需要放在形参声明 的 最后
-
6.在 一个方法的形参位置,最多只能声明一个可变个数形参
实例说明
package com.itguigu.java;
/*
* 可变个数形参的方法
* 1.jdk5.0新增的内容
* 2.具体使用:
* 可变个数形参的格式:数据类型...变量名
* 当调用可变个数形参的方法时候,传入的参数个数可以是:0个、1个、2个或多个
* 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载。
* 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不够成重载
* 可变个数形参在方法的形参中,必须声明在末尾
* 可变个数形参在方法的形参中,最多只能声明一个可变形参。
*/
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest test = new MethodArgsTest();
test.show(12);
test.show("hello");
test.show("hello", "world");
}
public void show(int i) {
}
public void show(String s) {
System.out.println("show(String)");
}
public void show(String ... strs) {
System.out.println("show(String...strs)");
for(int i=0; i<strs.length;i++) {
System.out.println(strs[i]);
}
}
// public void show(String[] args) {
//
// }
public void show(int i, String ... strs) {
}
}
3.3.5、再谈方法 3.0 :方法参数的值传递机制
方法,必须由其 所在类或对象调用才有意义。若方法含有参数:
- 形参 :方法声明时的参数
- 实参: 方法调用时 实际传给形参的参数值
Java里方法的参数传递方式只有一种: 值传递 。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受 影响 。
- 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
- 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
值传递过程说明:
例2;
例3
引用传递过程说明:
例2:
4、面向对象 特征之一:封装和隐藏
为什么需要封装?封装的作用和含义?
我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
我们 程序设计追求 “高内聚,低耦合
”。隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性 。通俗的说 把该隐藏的隐藏起来,该暴露的暴露出来 。 这就是封装性的设计思想。
- 高内聚 :类 的内部数据 操作细节自己完成,不允许外部干涉;
- 低耦合 仅对外暴露 少量的 方法 用于 使用 。
信息的封装和隐藏
Java中通过将数据声明为私有的 ( 再提供公共的 public方法 getXxx 和 setXxx 实现对该属性的操作 以实现下述目的:
- 隐藏 一个类中 不需要对外提供的 实现细节;
- 使用者只能通过事先定制好的 方法来访问数据 可以方便地加入控制逻辑限制对属性的不合理操作;
- 便于修改 增强代码的可维护性;
package com.itguigu.java;
/*
* 面向对象的特征一:封装与隐藏
* 一、问题的引入:
* 当我们创建一个类的对象以及,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到
* 属性的数据类型和存储范围的制约,除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值
* 加入额外的制约条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。同时,我们需要
* 避免用户再使用"对象.属性"的方式对属性进行赋值,则需要将属性声明为私有的(private)。
* -->此时,针对于属性就体现了封装性。
*
* 二、封装性的体现
* 我们将类的属性私有化(private),同时,提供公共(public)的方法来获取(getXxx)和设置(setXxx)此属性的值。
*
* 拓展:封装性的体现:1、如上。2、不对外暴露的私有方法。3、单例模式。等等
*
*三、封装性的体现,需要权限修饰符来配合。
* 1.Java规定的4种权限(从小到大):private,缺省,protected,public
* 2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类。
* 3.具体的:4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类。
* 修饰类的话,只能使用:缺省、public。
*
*总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及内部结构在被调用的时候的可见性的大小。
*/
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.name = "大黄";
//a.age = 1;
//a.legs = 4;
a.show();
//a.legs = -4;
a.setLegs(10);
a.show();
System.out.println(a.getLegs());
}
}
class Animal{
String name;
private int age;
private int legs; //腿的个数
public void setLegs(int l) {
if(l>=0 && l%2==0) {
legs = l;
}else {
legs = 0;
}
}
public int getLegs() {
return legs;
}
public void eat() {
System.out.println("动物进食");
}
public int getAge() {
return age;
}
public void setAge(int a) {
age = a;
}
public void show() {
System.out.println(name + "," + age + "," + legs);
}
}
4.1、四种访问权限修饰符
5、构造器 ——构造方法
构造器的特征
- 它具有与类相同的名称
- 它不声明返回值类型。(与声明为 void 不同)
- 不能被 static 、 final 、 synchronized 、 abstract 、 native 修饰,不能有return 语句返回 值
构造器的作用 :
- 创建对象;给对象进行初始化
如: Order o = new Order (); Person p = new Person (“Peter”,15);
如同 我们规定每个“人”一出生就必须先洗澡,我们就可以在“人” 的构造 器 中 加入完成“洗澡”的程序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们要“洗澡”了。
构造器的分类 :
根据参数不同,构造器可以分为如下两类:
- 隐式无参构造器(系统 默认 提供)
- 显 式 定义一个或多个 构造器(无参、有参)
注 意:
-
Java 语言中,每个类都至少有一个 构造器
-
默认构造器的修饰符与所属类的修饰符一致
-
一旦 显式定义了 构造器, 则系统 不再 提供默认 构造 器
-
一个类可以创建多个 重载 的构造器
-
父 类的 构造器不可被子类继承
构造器的使用 :
5.1、构造器重载
6、关键字1 —— this
this是什么?
-
在 Java 中, this 关键字比较难理解,它 的作用和其词义很接近。
-
它在方法内部使用,即这个方法所属对象的引用;
-
它在构造器内部使用,表示该构造器正在初始化的对象。
-
-
this 可以 调用类的属性、方法 和 构造 器
-
什么时候使用 this 关键字呢?
-
当在方法内需要用到调用该方法的对象时,就用 this 。具体的:我们可以用this 来 区分 属性 和 局部变量 。
比如:this.name = name。 -
1.在 任意 方法或构造器内 ,如果使用当前类的成员变量或成员方法可以在其前面添加 this增强程序的 阅读 性。过,通常我们都习惯省略 this 。
-
2.当 形参与成员变量同名时,如果在方法 内或构造器内需要使用成员变量,必须添加 this 来表明该变量是类的成员 变量
-
3.使用 this 访问属性和方法时,如果在本类中未找到,会从父类中查找
-
4.this可以作为一个 类 中构造 器相互 调用的特殊格式
-
注意:
- 可以 在类的构造器中使用 " 形参列表 的方式,调用本类中重载的其他的构造器!
- 明确 :构造器中不能通过 "this( 形参列表 )"的方式调用自身构造器
- 如果 一个类中声明了 n 个构造器,则最多有 n -1 个构造器中使用了"this( 形参列表 )"
- “this( 形参列表 )” 必须声明在类的构造器的首行!
- 在 类的一个构造器中,最多只能声明一个"this( 形参列表 )"