二者都是一种思想,面向对象是相对于面向过程而言的。
面向过程(POP),强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象(OOP),将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等
面向对象思想比面向过程思想更高级
程序员从面向过程的执行者转化成了面向对象的指挥者
面向过程思想:算法+数据结构
面向对象思想:数据结构+算法
看一个实例来理解面向过程和面向对象的区别,
人开车上班
package com.nie.classandobject; /** * @author nzy * @create 2021-12-16 17:18 */ public class Class1 { //面向过程和面向对象的区别 //举例:开车上班 } //面向过程 class POPTest{ //启动车 public void startCar(){ System.out.println("小王启动车"); } //开车中 public void driverCaring(){ System.out.println("小王开车中"); } //到目的 停车锁车 public void stopCar(){ System.out.println("小王停车中"); } } //面向对象编程 class Car{ public void startCar(){ System.out.println("启动车"); } //开车中 public void driverCaring(){ System.out.println("开车中"); } //到目的 停车锁车 public void stopCar(){ System.out.println("停车中"); } } class Person{ //不关心Car内部方法的实现, public void driverCar(Car car){ car.startCar(); car.driverCaring(); car.stopCar(); } }
面向对象分析方法分析问题的思路和步骤:
面向对象程序设计的重点是类的设计
类的设计,就是类的成员的设计
面向对象程序设计(简称OOP)是当今主流的程序设计范型,它已经取代了20世纪70年代的“结构化”过程化程序设计开发技术。Java是完全面向对象的,必须熟悉OOP才能够编写Java程序。
面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。程序中的很多对象来自标准库,还有一些是自定义的。究竟是自己构造对象,还是从外界购买对象完全取决于开发项目的预算和时间。但是,从根本上说,只要对象能够满足要求,就不必关心其功能的具体实现过程。在OOP中,不必关心对象的具体实现,只要能够满足用户的需求即可。
客观存在的事物皆为对象 ,所以我们也常常说万物皆对象。
类(Class)和对象(Object)是面向对象的核心概念
面向对象程序设计的重点是类的设计,类的设计就是设计类的成员
类
类的语法格式
修饰符 class 类名 { 属性声明; 方法声明; }
对象的创建(实例化)
创建对象语法: 类名 对象名 = new 类名();
使用“对象名.对象成员”的方式访问对象成员(包括属性和方法)
如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰。
类访问机制
属性:类中的成员变量
语法格式:
修饰符 数据类型 属性名 = 初始化值 ;
// 属性 : 姓名, 年龄 private String name; int age;
可以不赋值,默认的值是
元素类型 | 元素默认初始值 |
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0 |
char | 0 或写为:’\u0000’(表现为空) |
boolean | false |
引用类型 | null |
属性分类:成员变量和局部变量
成员变量 | 局部变量 | |
声明的位置 | 直接声明在类中 | 方法形参或内部、代码块内、构造器内等 |
修饰符 | private、public、static、final等 | 不能用权限修饰符修饰,可以用final修饰 |
初始化值 | 有默认初始化值 | 没有默认初始化值,必须显式赋值,方可使用 |
内存加载位置 | 堆空间 或 静态域内 | 栈空间 |
在虚拟机中:非static存在于堆中,static存在于常量池中
方法(函数):描述类具备的某种行为,用来完成某个功能操作,
将功能封装为方法的目的是,可以实现代码重用,简化代码
声明格式
修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){ 方法体程序代码 return 返回值; }
修饰符:public,缺省,private,protected等
返回值类型:没有返回值:void。有返回值,声明出返回值的类型。与方法体中“return返回值”搭配使用
方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意”
形参列表:可以包含零个,一个或多个参数。多个参数时,中间用“,”隔开
返回值:方法在执行完毕后返还给调用它的程序的数据
方法只有被调用时才会执行
形参:方法传递的参数
实参:方法调用时实际传给形参的参数值
// 行为 : 学习 public void study(String language){//language 形参 System.out.println("学习"+language); int num1 = 3;//局部变量 }
方法参数的值传递机制:实际参数值的副本(复制品)传入方法内,而本身参数不受影响,本身参数和副本都引用同一个对象,所以实参不是按引用调用的。
形参是基本数据类型:将实参基本数据类型变量的数据值传给形参
形参是引用数据类型:将实参引用数据类型变量的地址值传递给形参
方法可以修改引用数据的值,而不能修改基本数据的值(方法进入栈内存)
方法重载:
概念:在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同
特点:与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或者参数类型)调用时根据方法参数列表不同来区分
方法重写(Override):
定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法。
可变形参的方法:
jdk5中提供了可变形参机制,调用方法时可以传递多个参数
1. 声明格式:方法名(参数的类型名 ...参数名)
2. 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个
3. 可变个数形参的方法与同名的方法之间,彼此构成重载
4. 可变参数方法的使用与方法参数部分使用数组是一致的
5. 方法的参数部分有可变形参,需要放在形参声明的最后
6. 在一个方法的形参位置,最多只能声明一个可变个数形参
public class MethodArgsTest { public static void main(String[] args) { MethodArgsTest test = new MethodArgsTest(); test.show(12); test.show("hello"); test.show("hello","world"); test.show(); test.show(new String[]{"AA","BB","CC"}); } 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[] strs){ // // } //The variable argument type String of the method //show must be the last parameter // public void show(String ...strs,int i){ // // } }
源码中经常使用
递归方法
递归方法:一个方法体内调用它自身。
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
// 例:计算1-n之间所有自然数的和 public int getSum(int n) { if (n == 1) { return 1; } else { return n + getSum(n - 1); } }
java中使用构造器(构造函数)来创建对象,构造器是一种特殊的方法,用来初始化对象
编写规范:
作用:创建对象;给对象进行初始化
语法格式:
修饰符 类名 (参数列表) {
初始化语句;
}
Person p;//此时并没有创建对象,必须new //创建一个Date对象 Date date = new Date(); //Date的构造方法 public Date() { this(System.currentTimeMillis()); }
一个类没有编写构造器时,默认会提供一个无参的构造器,并将所有的实例字段设置为默认值
根据参数不同,构造器可以分为如下两类:
注 意:
调用父类的构造器
子类中所有的构造器默认都会访问父类中空参数的构造器
当父类中没有空参数的构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器。同时,只能”二选一”,且必须放在构造器的首行
如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有无参的构造器,则编译出错
初始化块,在类中声明,只要构造类的对象,这个代码块就会执行,
作用:用来初始化类、对象
静态代码块和非静态代码块
静态代码块:用static 修饰的代码块
非静态代码块:没有static修饰的代码块
代码块不常见,直接将初始化代码放在构造器中执行会更好
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
Inner class的名字不能与包含它的外部类类名相同;
分类: 成员内部类(static成员内部类和非static成员内部类)局部内部类(不谈修饰符)、匿名内部类
和外部类不同,Inner class还可以声明为private或protected
可以调用外部类的结构
Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;(懒汉式单例模式的一种写法)
成员内部类作为类的角色:
注意:
1. 非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员。
2. 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式
3. 成员内部类可以直接使用外部类的所有成员,包括私有的数据
4. 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的
public class InnerClassTest { public static void main(String[] args) { //创建Dog实例(静态的成员内部类): Person.Dog dog = new Person.Dog(); dog.show(); //创建Bird实例(非静态的成员内部类): // Person.Bird bird = new Person.Bird();//错误的 Person p = new Person(); Person.Bird bird = p.new Bird(); bird.sing(); System.out.println(); bird.display("黄鹂"); } } class Person{ String name = "小明"; int age; public void eat(){ System.out.println("人:吃饭"); } //静态成员内部类 static class Dog{ String name; int age; public void show(){ System.out.println("卡拉是条狗"); // eat(); } } //非静态成员内部类 class Bird{ String name = "杜鹃"; public Bird(){ } public void sing(){ System.out.println("我是一只小小鸟"); Person.this.eat();//调用外部类的非静态属性 eat(); System.out.println(age); } public void display(String name){ System.out.println(name);//方法的形参 System.out.println(this.name);//内部类的属性 System.out.println(Person.this.name);//外部类的属性 } } public void method(){ //局部内部类 不常用 class AA{ } } { //局部内部类 class BB{ } } public Person(){ //局部内部类 class CC{ } } }
Java权限修饰符public、protected、(缺省)、private置于类的成员定义前,用来限定对象对该类成员的访问权限。
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
private | Yes | |||
(缺省) | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |
对于class的权限修饰只可以用public和default(缺省)。
匿名:没有名字
匿名创建的对象只使用一次
可以创建匿名对象后调用该对象的方法
public class PersonTest { public void save(Person person){ //业务逻辑 } public static void main(String[] args) { PersonTest test1 = new PersonTest(); test1.save(new Person());//new Person() 就是匿名对象。匿名没有名字 new PersonTest().save(new Person()); //创建了一个匿名Runnable子类的对象 new Thread(new Runnable() { @Override public void run() { } }); } }