Java面向对象目录
⛳ Java面向对象
🐾 一,面向对象概述
💭1.1,面向过程和面向对象
1,面向对象
面向过程,强调的是功能行为,以函数为最小单位
2,面向过程
面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象,分类,继承,聚合,多态等。
3,面向对象的三大特征
- 封装(Encapsulation)
- 继承(Inheritance)
- 多态(Polymorphism)
面向对象的七大原则:
-
单一职责原则(Single Responsibility Principle)
每一个类应该专注于做一件事。
-
里氏替换原则(Liskov Substitution Principle)
超类存在的地方,子类是可以替换的。
-
依赖倒置原则(Dependence Inversion Principle)
实现尽量依赖抽象,不依赖具体实现。
-
接口隔离原则(Interface Segregation Principle)
应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。
-
迪米特法则(Law Of Demeter)
又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。
-
开闭原则(Open Close Principle)
面向扩展开放,面向修改关闭。
-
组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
尽量使用合成/聚合达到复用,尽量少用继承。原则: -个类中有另一个类的对象。
关于组合和聚合参考:https://zhuanlan.zhihu.com/p/359672087`
📢1.2,概述
类(Class)和对象(Object)是面向对象的核心概念。
-
类是对一类事物的描述,是抽象的、概念上的定义
-
对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
-
可以理解为:类=抽象概念的人;对象=实实在在的某个人
-
面向对象程序设计的重点是类的设计
-
类的设计,其实就是类的成员的设计
🏭 1.3,类的成员
现实生物世界中的细胞又是由什么构成的呢?细胞核、细胞质、… 那么, Java中用类class来描述事物也
是如此。常见的类的成员有:
- 属性:对应类中的成员变量
- 行为:对应类中的成员方法
Field =属性=成员变量,Method = (成员)方法=函数
public class Persion1 {
String name;
int age;
/**
* sex: 1 表示是男性
* sex: 0 表示是女性
*/
int sex;
public void study(){
System.out.println("studying");
}
public void showAge(){
System.out.println("age: " + age);
}
public int addAge(int i){
age += i;
return age;
}
}
🎁 1.4,内存解析
1.4.1,创建对象
class Person{
int age;
void shout(){
System.out.println("Oh,my god! I am " + age);
}
}
Person p1 = new Person();
执行完后的内存状态。其中类定义如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W9DzcOUD-1689854454303)(https://gitee.com/galloping_pony/img-home/raw/master/%E6%9C%AA%E5%91%BD%E5%90%8D%E7%BB%98%E5%9B%BE.drawio.png)]
1.4.2,使用对象
class PersonTest{
public static void main(String[] args){
Person p1 = new Person();
Person p2 = new Person();
p1.age = -30;
p1.shout();
p2.shout();
}
}
1.4.3,内存区域
- 堆(Heap) ,此内存区域的唯一 目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
- 通常所说的栈(Stack) , 是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、 char、 short、 int、 float、 long 、double)、对象引用(reference类型, 它不等同于对象本身,是对象在堆内存的首地址)。方法执行完,自动释放。
- 方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
☁ 1.5,属性(Field)
1.5.1,变量的分类
- 在方法体外,类体内声明的变量称为成员变量。
- 在方法体内部声明的变量称为局部变量。
成员变量 | 局部变量 | |
---|---|---|
声明的位置 | 直接声明在类中 | 方法形参或内部,代码块内,构造器内等 |
修饰符 | private,public,static,final等 | 不能用权限修饰符,可以用final修饰 |
初始化值 | 有默认初始化值 | 没有默认初始化值,必须显式赋值,方可使用 |
内存加载位置 | 堆空间 或 静态空间 | 栈空间 |
1.5.2,成员变量默认初始化值
🎨 1.6,方法(Method)
- 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
- 将功能封装为方法的目的是,可以实现代码重用,简化代码
- Java里的方法不能独立存在,所有的方法必须定义在类里。
格式:
修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ...){
方法体程序代码
return 返回值;
}
1.6.1,方法的重载
在同一个类中,允许存在一个以 上的同名方法,只要它们的参数个数或者参数类型不同即可。
重载的特点:与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。
调用时,根据方法参数列表的不同来区别。
// 返回两个整数的和
int add(int x, int y){return x+y;}
// 返回三个整数的和
int add(int x,int y,int z){return x+y+z;}
// 返回两个小数的和
double add(double x, double y){return x+y;}
使用案例:
编写程序,定义三个重载方法并调用。方法名为mOL。
-
三个方法分别接收一个int参数、两个int参数、一个字符串参数。分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。
-
在主类的main ()方法中分别用参数区别调用三个方法。
定义三个重载方法max(),第一个方法求两个int值中的最大值,第二个方法求两个double值中的最大值,第三个方法求三个double值中的最大值,并分别调用三个方法。
public class OverloadExer {
// 1. 如下的三个方法构成重载
public void mOL(int i){
System.out.println(i * i);
}
public void mOL(int i,int j){
System.out.println(i * j);
}
public void mOL(String s){
System.out.println(s);
}
//2.如下的三个方法构成重载
public int max(int i,int j){
return (i > j)? i : j;
}
public double max(double d1,double d2){
return (d1 > d2)? d1 : d2;
}
Public double max(double d1,double d2,double d3){
double max = (d1 > d2)? d1 : d2;
return (max > d3)? max : d3;
}
}
1.6.4,可变参数
//JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型变量
public static void test(int a ,String[] books);
//JDK5.0:采用可变个数形参来定义方法,传入多个同一类型变量
public static void test(int a ,String… books);
- 声明格式:方法名(参数的类型名 …参数名)
- 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个
- 可变个数形参的方法与同名的方法之间,彼此构成重载
- 可变参数方法的使用与方法参数部分使用数组是一致的
- 方法的参数部分有可变形参,需要放在形参声明的最后
- 在一个方法的形参位置,最多只能声明一个可变个数形参
public class Test2 {
public void show(String[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public void display(String... arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public void display(String name, int... arr) {
System.out.println("name=" + name);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args) {
Test2 t2 = new Test2();
String[] strs = new String[]{"a", "b", "c"};
t2.show(strs);
System.out.println("--------------");
String[] strs2 = new String[]{"aa", "bb", "cc"};
t2.display(strs2);
System.out.println("--------------");
//可变参数用法
t2.display();
// t2.show(); //报错
System.out.println("--------------");
t2.display("mickey", "a", "b");
t2.display("mickey", 1, 2, 3);
}
}
1.6.3 参数传递
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
- 形参:方法声明时的参数
- 实参:方法调用时实际传给形参的参数值
Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
- 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
- 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
1.6.4,递归方法传递
递归方法:一个方法体内调用它自身。
- 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
public class RecursionTest {
public static void main(String[] args) {
// 例1:计算1-100之间所有自然数的和
// 方式一:
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println(sum);
// 方式二:
RecursionTest test = new RecursionTest();
int sum1 = test.getSum(100);
System.out.println(sum1);
System.out.println("*****************");
int value = test.f(10);
System.out.println(value);
}
public int getSum(int n) {// 3
if (n == 1) {
return 1;
} else {
return n + getSum(n - 1);
}
}
public int getSum1(int n) {
if (n == 1) {
return 1;
} else {
return n * getSum1(n - 1);
}
}
}