java面向对象


面向过程面向对象

  • 面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做
    在这里插入图片描述

  • 面向对象:强调的是具备功能的对象,以类|对象为最小单位,考虑谁来做

{
   打开(冰箱){
     冰箱.open();
     }
   抬起(大象){
      大象.进入(冰箱);
      }
   关闭(冰箱){
      冰箱.闭合();
      }
}
冰箱{
}
大象{
}

面向对象的两个元素: 类和对象(实例),类的设计其实是设计类的成员
类的实例化=创建类的对象
类和对象的关系:我们和控制台交互的时候,需要提供一个类,API提供了Scanner类,创建Scanner对象,通过对象去调用方法,去完成和控制台的交互

1.java类及类的成员

1.1属性、方法、对象和类

  • 属性=成员变量=field=域、字段
  • 方法=成员方法=函数=method
  • 如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性(非static),意味着:如果修改一个对象的属性值,不影响另外一个对象的属性值
  • 属性和方法的调用: 对象.属性;对象.方法。通过创建对象,实例化来调用属性方法
  • 如果创建了一个类的多个对象,多个对象是独立的拥有一套类的属性

1.2内存解析

链接: 参考.
引用类型的变量,只能存储null或者地址
java程序在运行时,在内存(ROM)中划分5片空间进行数据的存储,分别是1:寄存器。2:本地方法区。3:方法区。4:栈。5:堆。
最重要的是
1.堆:是运行时的数据区,类的对象从堆中分配空间。通过new等指令建立,通过垃圾回收器来销毁。优势在于可以动态的分配内存空间,需要多少内存空间不必事先告诉编译器,因为在运行时是动态分配的。但是缺点是,由于需要在运行时动态分配内存,所以存取速度较慢。
2.栈:存放一些基本数据类型的变量(byte,short,int,long,float,double,boolean,char)和对象的引用,先进后出

  • :主要存放局部变量,定义在方法中的,和基本类型的变量
  • :主要存放对象实例,new出来的(包括类对象以及数组对象,字符串对象这种),真实的创建对象的实体都在堆对象中,包括数组
  • 方法区:加载的类信息,常量,静态变量

在这里插入图片描述
代码解析

  • 第一行:new了一个对象,new的对象实体都存储在堆中,对象实体有一个首地址值(十六进制表示 ),然后通过“等号=”操作将右边数据赋值到左边(赋过来的是一个地址),p1实际上是定义在main方法中的,是一个局部变量,存储在栈中。类中有三个属性,属性存储在堆空间中,在造好的对象中,属性有值(没有赋值的即为默认值)
  • 第四行:new了一个对象,重新在堆空间中造了一个对象,包括实体和首地址值。将地址值赋给栈空间中的p2(p2是定义在main方法中的,是一个局部变量,在栈中),通过地址值,栈空间中的p2对象指向堆空间中的person实体
  • 第五行:p3是p1赋值的地址值,p1存储的是什么,就传什么值,p1存储的是地址值,所以传给p3的也是地址值,顺着地址值找到了堆空间中的结构,p3不是新创建的对象,是新声明的变量,p1和p3指向堆空间中的同一个对象实体,p3将age属性修改之后,如果p1再去调用age属性,属性值也改变了,因为是同一个对象实体。

1.3类中属性的使用

1.局部变量:方法中的变量都是局部变量,没有默认值(所以需要提前定义好),存储在栈中
2.成员变量: 在类中,方法之外,有默认值,存储在堆中
静态变量:在方法区中
(一)相同点:

  • 1.定义变量的格式:数据类型 变量名 = 变量值
  • 2.先声明,后使用
  • 3.变量都有其对应的作用域

(二)不同点:
2.1.在类中声明的位置不同(变量的声明:前面带一个类型的:String food)

  • 属性(成员变量):直接定义在类的一对{}内,有默认值,存储在堆中。
  • 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量 - 形参

2.2.关于权限修饰符的不同

  • 属性:可以在声明属性时,指明其权限,使用权限修饰符
  • 局部变量:不可以使用权限修饰符,也可以理解为其权限修饰由对应的方法声明

常用的权限修饰符:private、public、缺省、protected;(没有写的就表示缺省),权限表示被调用时候的可见性。

2.3默认初始化值的情况

  • 属性:类的属性,根据其类型,都有默认初始化值。
    整型(byte、short、int、long):0
    浮点型(float、double):0.0
    字符型(char):0
    布尔型(boolean):false
    引用数据类型(类、数组、接口):null
  • 局部变量:没有默认初始化值:意味着局部变量在调用前需要被初始化赋值——显式赋值
    特别的:形参在调用时,我们赋值即可

2.4.在内存中加载的位置:

  • 属性:加载到堆空间中(非static的)
  • 局部变量:加载到栈空间

属性:存储在堆空间中,在造好的对象里面
属性:类成员变量不全都是属性,只有能够访问到的成员变量才是属性,也就是成员变量必须有set和get方法,一般来说,set/get方法名,去掉set/get后,将剩余部分首字母小写得到的字符串就是这个类的属性。
1.属性的名字不是由成员变量决定的。通常set方法和get方法的名字是set或者get加上成员变量的名字,成员变量的首字母要变成大写。而属性的名字就是去掉set或者get,然后把首字母变成小写。从这两个命名规则可以看出,通常属性名与成员变量的名字是一致的。但是,如果在写set方法和get方法的时候,没有按照默认的规则写,则属性名字和成员变量名字就一样了

1.4 方法的声明

权限修饰符 返回值列表 方法名(形参列表){方法体}
1.4.1权限修饰符

  • public、private、缺省、protected

1.4.2返回值

  • 如果有返回值,必须要指明返回值的类型,方法体内必须加return关键字;如果有if语句,要记得必须全局return;return后不能有表达式。
  • 如果没有返回值,方法声明时使用void。通常没有return,但是如果是同return的话,只能"return;",表示结束此方法的意思

1.4.3形参列表

  • 格式:数据类型1 形参1,数据类型2 形参2

1.4.4说明

  • 方法的使用中,可以调用当前类的属性或方法
  • 特殊的,还有递归方法
  • 方法中不能再定义方法

1.5 对象数组的内存解析

  • 由对象构成了string
    在这里插入图片描述

  • 第一行,new了一个数组,数组的类型是引用类型,数组的元素可以为任意类型,这里为Student类型

  • 栈中,声明了一个stus变量,堆中,定义了长度为5的数组,没有给数组的元素赋值,所以都为null

  • stu[0] = new Student();在堆中开辟了一个新的地址
    在这里插入图片描述

  • 引用类型的变量只能存放null或者地址

  • stus[0] = new Student();new之后在堆中开辟一个新的地址,并把这个地址赋值给stus[0]这个引用变量

  • 因为stus[1]是null,所以stus[1].number回报空指针异常

1.6匿名对象的使用

  • 没有显示的赋给一个变量名
  • 以上是两个对象

1.7 方法的重载

  • 重载:发生在本类或者其子类中,具有相同的方法名。参数列表不同,返回值类型可以相同也可以不同方法名相同,参数列表(参数个数、参数类型)必须不一样,返回值类型可相同可不同 ,总结,重载就是针对不同情况写不同的方法,例如同一个类中的不同构造方法跟方法的权限修饰符、形参变量名、返回值类型、方法体都没关系

  • 重写:发生在父类和子类之间,方法名相同,参数相同,返回值类型相同,访问权限不能比父类中被重写的方法的访问权限低,比如父类是public,那么子类中该方法不能是protected,子类和父类在同一个包中,子类可以重写父类所有方法,除了声明为final和private,总结,具体的实现类对于父类的方法不满意,需要写一个满足自己要求的方法。

  • 一个类中可以有多个同名的方法,参数列表不能相同。

1.8可变个数的形参

public void show(int i){}
public void show(String s){}
public void show(String ... strs){}
  • 当调用可变参数的方法时,实参的个数可以是0,1,2……
  • 可变个数形参的方法与本类中方法名相同,形参不同之间的方法间构成了重载
  • 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不能共存

1.9方法参数的值传递机制

  • 如果变量是基本数据类型,此时赋值的是变量所保存的数据值
  • 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值,真实的对象存在了堆中,而变量存在栈中,只保存了地址
  • 引用类型的变量只能存储null或者地址值

1.10方法形参的传递机制:值传递

  • 形参:方法定义时,声明的小括号内的参数
  • 实参:方法调用时,实际传递给形参的数据

值传递机制

  • 如果参数是基本数据类型,此时实参赋给形参真实存储的数据值
  • 如果参数是引用数据类型,此时实参赋给形参的是真实存储数据的地址值
  • 链接: 尚硅谷210 .

1.11 构造器、构造方法

构造器的作用

  • 创建对象
  • 初始化对象的属性

说明

  • 如果没有显示的定义类的构造器的话,则系统提供一个空参的构造器,构造器权限和类权限相同
  • 定义构造器的格式:权限修饰符 类名(形参列表){}
  • 一个类中定义的多个构造器彼此构成重载
  • 一旦显示的定义了类的构造器,系统不再提供默认的空参构造器
  • 一个类中,至少有一个构造器

总结

  • 默认初始化值
  • 显式初始化值
  • 构造器中赋值
  • 通过“对象.方法”或者“对象.属性”的方式

1.12代码块

在这里插入图片描述

1.13接口

1.接口中定义的静态方法,只能通过接口来调用,实现接口的子类也不能调用
2.通过 实现类的 对象,可以调用接口中的默认方法,如果 实现类重写了默认方法,调用后调用的是 重写之后的方法
3.如果子类(实现类)继承的父类 和 实现的接口中声明了同名同参数的 默认方法,那么子类在没重写该方法的情况下,调用的是父类中的该方法
4.如果实现类实现了多个接口,而这多个接口中定义了同名同参数的 默认方法;如果实现类没有重写该方法,报错
抽象类与接口的异同:
相同点:都有抽象方法,不能被实例化
不同点:
抽象类单继承,接口多继承
java8之前,接口只能有常量和抽象方法
java8,接口中可以有静态方法和默认方法
java9,接口新增了私有方法

1.14内部类

1.15包装类

Integer i1 = new Integer(1)Integer i2 = new Integer(1)sout(i1==i2);//false,比较的是两个对象
Integer i1 = 1; 
Integer i2 = new Integer(1);
sout(i1==i2);//false,i1自动装箱,比较的仍是两个对象
Integer i1 = 1;
Integer i2 = 1sout(i1==i2);//true,自动装箱缓存机制,返回的同一个对象给i1和i2
Integer i1 = 126;
Integer i2 = 126;
sout(i1==i2);//此时==返回true
Integer i1 = 900;
Integer i2 = 900;
sout(i1==i2);//此时==返回false
//在-128~127的整数范围内都会存在自动拆装箱的缓存,所以126 和 900 的区别就在这里(126两个都是返回的同一个对象,900超过范围了返回的不是同一个对象)

两个都是包装类最好用.equals()方法比较,这样比较的是值。 如果一个是int类型,一个是包装类,那么可以直接用==,因为包装类自动拆箱为int类型了,所以这时候比较的也是值,而不会存在一个是基本类型,一个是引用类型不能比较,这就是自动拆装箱

拓展 javabean

  • 公共的类
  • 无参的公共的构造器
  • 私有属性,且有对应的get、set方法

2.面向对象的三大特征

2.1封装性

  • 将属性私有化,提供public方法来get获取和set设置属性
  • 还包括不对外暴露的私有方法和单例模式

封装性的体现,需要权限修饰符来配合

  • private、缺省、protected、public
  • 可以修饰类及类的内部结构:属性、方法、构造器、内部类
  • 修饰类:只能public和缺省

java提供了四种权限修饰来修饰类和类的内部结构,体现类及类的内部结构在被调用时的可见性的大小
在这里插入图片描述

2.2继承性

1.继承性的好处

  • 减少了代码的冗余,提高了代码的复用性
  • 便于功能的扩展
  • 为之后的多态性的使用,提供了前提

2.继承性的格式 class A extends B{}

  • A:子类、派生类 subclass
  • B:父类、超类、基类 superclass
  • 一旦子类A继承父类B以后,子类A就获取了父类B中声明的所有的属性和方法
    特别地,父类中声明为private的属性或方法,子类继承父类之后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
    属性private,调用public的set和get方法;方法private,则将该方法写入其他方法中调用
  • 子类继承父类之后,还可以声明自己特有的属性或方法:实现功能的扩展
  • 子类和父类的关系,不同于子集和集合的关系

3.继承性的规定

  • 一个类可以被多个子类继承
  • java中类的单继承性:一个类只能有一个父类

4.Object类

  • 如果没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
  • 所有的java类(除java.lang.Object类之外)都直接或间接的继承java.lang.Object类
  • 所有的java类都具有java.lang.Object类声明的功能

2.2.1重写

1.重写:子类继承父类
2.要求:方法名和形参列表都一样
3.应用:重写之后,当创建子类对象以后,通过子类对象调用子父类的同名同参数的方法时,实际执行的是子类重写父类的方法。
4.重写的规定:

  • 方法的声明:权限修饰符 返回值类型 方法名(形参列表){ 方法体}
  • 子类重写的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
  • 子类重写的方法 的 权限修饰符 不小于 父类被重写的方法 的权限修饰符
  • 子类不能重写 父类中 权限为private的方法(不报错,子类中算是 一个新方法),只能继承,不能重写
  • 返回值类型
    • 父类是void,则子类是void
    • 父类是A类,则子类是A类或者A类的子类
    • 父类是基本数据类型,则子类是相同的基本数据类型
    • 子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static(不是重写)

2.3多态性

1.理解:可以理解为一个事物的多种形态
2.对象的多态性:父类的引用指向子类的对象,子类的对象赋给父类的引用
3.多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法——虚拟方法调用;在编译期,只能调用父类中声明的方法,但在运行期,实际执行的是子类重写父类的方法。编译看左,运行看右;
4.多态性的使用前提:有类的继承关系;方法的重写

//Man和Woman都是Person的子类
Person p1 = new Person();
Person p2 = new Man();
Person P3 = new Woman()

5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
重载:在方法调用前,编译器就已经确定了所要调用的方法,称为“早绑定”或“静态绑定”
多态:只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,称为“晚绑定”或“动态绑定”
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
6.如何才能调用子类特有的属性和方法?

Man m1 = (Man)p2
//向下转型:试用强制类型转换符

使用强转时,可能出现ClassCastException的异常。
instanceof关键字:
a instanceof A:
1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中
2.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量

==和equals()的区别

一、==,运算符
1.可以使用在基本数据类型变量和引用数据类型变量中;
2.如果比较的是基本数据类型变量,比较变量保存的数据是否相等(不一定类型要相等)
如果比较的是引用数据类型变量,比较两个对象的地址值是否相同,两个引用是否指向同一个对象实体。
二、equals方法
1.只能适用于引用数据类型
2.object类中equals定义和==作用相同,比较两个对象的地址值是否相同,是否指向同一个对象实体
3.像String、Date、File、包装类都重写了Object类中的equals方法,重写以后,比较的不是两个引用的地址是否相同,而是两个对象的实体内容是否相同。
4.自定义类使用equals方法,通常比较两个对象的实体内容是否相同,需要重写。

toString

1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString

3.其他关键字

this、super、static、final、abstract、interface、package、import

3.1 this

  • this可以用来修饰:属性、方法、构造器
  • this修饰属性和方法
    • this为当前对象 或 当前正在创建的对象
    • 在类的方法中,可以使用this.属性和this.方法,调用当前对象属性和方法通常情况下,省略this,如果方法的形参和类的属性同名时,必须显式的使用this.变量,表明此变量是属性,而非形参
    • 在类的构造器中,可以使用this.属性和this.方法,调用当前正在创建的对象属性和方法通常情况下,省略this,如果构造器的形参和类的属性同名时,必须显式的使用this.变量,表明此变量是属性,而非形参
  • this修饰、调用构造器
    • 我们在类的构造器中,可以显式的使用"this(形参列表)"方法,调用本类中指定的其他构造器
    • 构造器中不能通过"this(形参列表)"方式调用自己
    • 如果一个类中有n个构造器,则最多有n-1个构造器中使用了"this(形参列表)"
    • "this(形参列表)"必须在当前构造器的首行
    • 构造器内部,最多只能声明一个”this(形参列表)“,用来调用其他的构造器
public Person(){}
public Person(String name){
  this();//调用空参的构造器
  this.name = name;
}
public Person(int age){
  this();//调用空参的
  this.age = age;
}
public Person(String name,int age){
  this(age);
  this.name = name;
}  

3.2package、import

在这里插入图片描述

5.3super

1.理解为:父类的
2.可以用来调用:属性、方法、构造器
3.super的使用

  • 在子类的方法或构造器中,通过使用”super.属性“或"super.方法"的方式,显示的调用父类中声明的属性或方法。但是,通常情况下,省略"super."
  • 当子类和父类中定义了同名的属性时,要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性",表明调用的是父类中声明的属性
  • 当子类重写了父类的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法

4.super调用构造器

  • 在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
  • "super(形参列表)"的使用,必须声明在子类构造器的首行
  • 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现
  • 在构造器的首行,没有显式的声明"this(形参列表)“或"super(形参列表)”,则默认调用的是父类中空参的构造器
  • 在类的构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器

5.子类对象实例化

  • 从结果上来看:(继承)
    子类继承父类以后,就获取了父类中声明的属性或方法
    创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
  • 从过程上来看:
    当通过子类的构造器创建子类对象时,一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,知道调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用
  • 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建一个对象,即为new的子类对象。

3.4static关键字

可以修饰:属性、方法、代码块、内部类
1.修饰属性(成员变量,不是局部变量)
1.1属性:分为静态属性和非静态属性(实例变量)
实例变量:创建了多个对象。每个对象独立地拥有一套类中的非静态属性,当修改其中一个对象的非静态属性时,不会导致其他对象中同样的属性值更改
静态变量(或类变量):多个对象共享同一个静态变量,当其中一个对象对静态变量修改时,会导致其他对象调用该静态变量时是修改过了的
1.2其他说明

  • 静态变量随着类的加载而加载。可以通过“类.静态变量”调用
  • 静态变量的加载要早于对象的创建
  • 由于类只会被加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中

2.修饰方法

  • 静态方法中只能调用静态的方法和属性
  • 非静态方法中,既可以调用非静态的方法和属性,也可以调用静态的方法和属性
  • 在静态的方法中,不能使用this、super关键字

3.单例设计模式
3.1定义:采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例
3.2如何实现
饿汉式 vs 懒汉式
饿汉式:
1.私有化类的构造器
2.内部创建类的对象
3.提供公共的静态的方法,返回类的对象
4.要求此对象也必须声明为静态的
懒汉式:
1.私有化类的构造器
2.声明当前类对象,没有初始化
3.声明public、static的返回当前类对象的方法
4.此对象也必须声明为静态的

3.5final关键字

final修饰类:此类不能被其他类继承
final修饰方法:此方法不可以被重写
final修饰变量:此时变量为常量,要大写
static final修饰属性:全局变量

static和abstract不能共用:abstract的目的是不能够造对象,让对象去调用抽象类的方法,抽象类里的方法没有方法体,如果类被声明为static的,则可以不通过造对象直接调用方法,矛盾。

abstract不可以和final共用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值