面向对象
什么是面向对象?
早期,程序开发是结构化程序设计语言
随着软件规模扩大,结构化语言的弊端就出现了,开发慢、质量不好
后来程序设计者就引入了面向对象的开发思想
面向过程:需要做什么操作,每次需要的时候,都去重新编写一遍
面向对象:将所有的操作,封装到方法中,然后通过对象,去调用方法,
执行想要的操作,这样就可以,一次编写,多次调用。
面向对象和面向过程的对比
比如要做菜:
面向过程:买菜->洗菜->切菜->做菜->吃菜
面向过程:去饭店->点菜->吃菜
区别:
面向对象极大地提高了代码的可维护性和扩展性
比如上面的例子
现在想换一些菜吃
面向过程,得把之前的过程再来一遍
面向对象,直接跟厨师说换一份菜
面向过程是具体化的,流程化的,解决问题需要一步步分析,一步步解决。
面向对象是模型化的,将来需要抽象出来一个类,在这个类中有解决问题的方法,将来我们只要通过这个类对象,调用方法就可以了,不用去关心具体的功能是怎么实现的,只负责用就可以。
优缺点:
面向过程优点:性能好,面向对象创建对象需要实例化,需要消耗内存空间
缺点:不易维护、不易复用、不易扩展
面向对象优点:易维护、易复用、易扩展
缺点:性能比面向过程差
面向对象的分类:
面向对象简称OO(object oriented),具体分为:
OOA(面向对象分析):在项目开始,分析需求的时候,引入类和对象思想
OOD(面向对象设计):在OOA的基础上,增加进一步的设计因素,主要产生设计的架构
以及将来平台相关政策,要设计出功能的接口
OOP(面向对象程序设计):根据OOD设计的接口,做出具体的实现,开始编程
面向对象的两个关键词:类 和 对象
类:对象的抽象称为类。
类是抽取了所有对象的共同的信息、功能的一个抽象。
对象:类的实例化称为对象。
对象就是有具体信息、具体功能的一个物体。
对象,用来描述一个客观的具体是实体,通过一组属性和方法构成
对象的两大特征:
属性:对象具有的各种特征(信息)
方法:对象可以执行的操作或具备的功能
Java中声明类和对象:要先创建类,然后再创建对象
1.声明类:类名表示要抽取的类
public class 类名{
}
2.声明对象的共同属性,声明在类中,
声明的方式遵循变量的声明方式,声明的时候可以不用赋值
public class 类名{
数据类型 属性1;
数据类型 属性2;
数据类型 属性3;
.....
}
3.声明对象的共同的功能,声明在类中,其实就是类中的方法
方法的声明,遵循之前方法的声明用法
public class 类名{
数据类型 属性1;
数据类型 属性2;
数据类型 属性3;
.....
public void 方法名1(){
}
public void 方法名2(){
}
}
4.将来想要使用类的属性、方法,就需要创建类的对象,对象名其实就是变量
main(){
类名 对象名 = new 类();
对象名.属性 = 值;
对象名.方法();
}
属性的初始值:
类的属性,声明后,系统会给一个默认值, 如果将来对象没有给属性赋值,那么使用的就是默认值
整数型 : 默认值为0
单精度浮点型 : 默认值是0.0f
双精度浮点型 : 默认值是0.0d
字符型char : ''
布尔型 : false
字符串 : null
其他的引用类型 : null
属性和方法的调用
语法:对象.属性;
对象.方法();
类的组成详解
1.属性
类的属性,也称为成员变量,可以不用赋初值,系统会提供默认值
整数型:默认值为0
单精度浮点型 : 默认值是0.0f
双精度浮点型 : 默认值是0.0d
字符型:char : ''
布尔型:false
字符串:null
其他的引用类型 : null
2.普通方法
是类的每个对象共享,也称为实例方法
方法的声明跟之前学习的方法声明方式相同,只不过修饰符现在是public
修饰符 返回值类型 方法名(参数列表){
方法体;
return;
}
3.构造方法(构造器/构造函数)
当我们在创建对象的时候,使用new关键字,调用的和类同名的方法,其实就是构造方法
比如:new Phone(); 这个Phone就是Phone类的构造方法
作用:其实就是用来实例化对象的。
如果一个类,没有构造方法,这个类就无法被实例化。
特点:
1.如果类中没有创建构造器,系统会默认提供一个无参构造器
如果自己声明了构造器,系统就不提供默认的构造器了
类似于:Phone phone=new Phone();
new Phone()就是系统提供的无参构造器
2.构造函数就是用来被调用后,实例化对象的,用在其他地方没有太多意义,一般都是和new关键字同时出现
3.构造器的方法名,和类名同名,没有返回值类型,没有return
修饰符一般都是public,构造器的参数可以有0个,1个,多个,参数一般就是这个类的属性
4.根据调用的构造器传入的参数来自动判断,调用的是哪个构造器
package com.day6.object;
//创建一个人类,有姓名、年龄、性别三个基本属性,每个人还有一个手机,
//人类都有自我介绍的方法,可以创建对象后,用来介绍自己的信息
//介绍内容为:我是xx,我的年龄是xx,我的性别是xx,我有一个xx品牌的手机,我花了xx钱买了这部手机
//人类还有一个打电话的方法,调用后,可以输出:我在用我的xx品牌的手机打电话
public class People {
//属性
String name;
int age;
String gender;
Phone phone;//手机是属性
//构造器(生成的快捷键 alt+insert)
//全参构造
public People(String name, int age, String gender, Phone phone) {
this.name = name;
this.age = age;
this.gender = gender;
this.phone = phone;
}
//无参构造
public People() {
}
//方法
public void info(){
System.out.println("我是"+name+",我的年龄是"+age+",我的性别是"+gender+
",我有一个"+phone.brand+"品牌的手机,我花了"+phone.price+"买了这部手机。");
}
//我在用我的xx品牌的手机,给xxx的xx手机打电话
public void call(People people){
System.out.println("我在用我的"+phone.brand+"品牌的手机给"
+people.name+"的"+people.phone.brand+"手机打电话!");
}
//toString()方法
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", phone=" + phone +
'}';
}
public static void main(String[] args) {
People p1 = new People();
p1.name="张三";
p1.age=20;
p1.gender="男";
p1.phone=new Phone();//对象作为属性,也需要赋值
p1.phone.brand="小米";
p1.phone.price=4599;
p1.info();
//通过全参构造创建的People对象p2
People p2 = new People("李四", 22, "男",
new Phone("华为"));
p1.call(p2);
}
}
方法重载:
分为构造方法重载和普通方法重载。
概念:在同一个类中,方法名相同,参数列表不同(包括参数类型、个数、顺序不同),
和返回值、修饰符无关。
调用重载的方法,会根据你调用的时候,实际传入的参数类型去判断调用的是哪个方法
package com.day6.object;
//写一个加法的方法重载示例,写一个add方法,可以传入参数,返回他们的求和结果
//最少得有3个add方法可以调用,调用的时候可以传入不同的参数
public class Practice<itar> {
public static int add(int i,int j){
return i+j;
}
//参数类型不同
public static double add(int i,double j){
return i+j;
}
//参数顺序不同
public static double add(double j,int i){
return i+j;
}
//参数个数不同
public static double add(int i, double j,int k){
return i+j+k;
}
public static void main(String[] args) {
System.out.println(add(2,3));
System.out.println(add(33,44.44));
System.out.println(add(5,33.3,55));
}
}
程序的执行流程以及对象在内存中的结构
1.当main()方法执行时,main()方法会从方法区进入到栈区
2.开始执行main()方法中的代码
(1)Phone phone = new Phone();
(2)phone.brand = "华为";
(3)phone.price = 4999.99;
(4)phone.call("张三");
3.当执行main方法中第一行代码 Phone phone = new Phone();
先在堆区开辟一个空间,存放new出来的Phone对象,并且把这个空间的引用地址赋给phone,
这个时候,这个空间中有Phone类的属性,属性值都是默认值,还有方法引用,指向方法区中的方法
4.执行第二行代码 phone.brand = "华为";
通过phone引用的地址值,找到对象在堆中的位置,
并且找到空间中的brand属性,给brand属性重新赋值
5.执行第三行代码 phone.price = 4999.99;
通过phone引用的地址值,找到对象在堆中的位置,
并且找到空间中的price属性,给price属性重新赋值
6.执行第四行代码 phone.call("张三");
通过phone引用的地址值,找到堆区的位置,找到空间中的方法引用,并且将指向的方法加载进栈
7.全部执行完之后,call方法会率先出栈,后续的main方法才会出栈
成员变量和局部变量
成员变量:声明在类中,方法外的变量
局部变量:声明在类中,方法中的变量
1.位置不同
成员变量在类中,方法外
局部变量在类中,方法内(方法声明上,或方法定义中)
2.内存中位置不同
成员变量在堆中
局部变量在栈中
3.生命周期不同
成员变量随着对象存在而存在,对象会被JVM的垃圾回收器单独回收
局部变量随着方法加载进栈而存在,方法结束出栈而消失
4.初始化调用不同
成员变量声明后不用赋初值,也能使用
局部变量,必须要赋初值才能使用
方法的参数传递
方法参数传递基本类型和引用类型的区别
方法传入的参数,只有两种类型,基本类型和引用类型
1.传递基本数据类型的时候,就是传递值本身,所以不会改变原来的值。
package com.day6.test;
//基本类型传递
public class TestMethod {
public void change(int a){
a = 20;
}
public static void main(String[] args) {
int a = 100;
System.out.println(a);//100
TestMethod t = new TestMethod();
t.change(a);
System.out.println(a);//100
}
}
2.传递引用类型的时候,传递的是引用的地址,所以会改变引用地址中变量的值。
package com.day6.test;
//引用类型传递
public class TestMethod1 {
public void change(Person person){
person.age = 30;
}
public static void main(String[] args) {
Person person = new Person();
person.age = 50;
System.out.println(person.age); //50
TestMethod1 t = new TestMethod1();
t.change(person);
System.out.println(person.age);//30
}
}
3.String类型是一个特殊的引用类型,传递的时候,按照值传递的方式传递。
package com.day6.test;
//String类型传递
public class TestMethod2 {
public void change(String s){
s = "hello";
}
public static void main(String[] args) {
String s = "world";
System.out.println(s); //world
TestMethod2 t = new TestMethod2();
t.change(s);
System.out.println(s); //world
}
}