1 面向对象
1,概述
面向对象其实就是面向类
- 我们前面讲了数组,当有多个数组需要遍历的时候,我们就把遍历的代码封装到了方法中,再次需要遍历的时候调用方法即可。提高代码的复用性。
- 如果我们的需求不断增加,(获取最值,逆序,排序。。。)我们需要封装的方法也就越来越多了。
所以我就想能不能把这些方法也进行封装呢?通过前面的学习我们知道类中可以存放方法。所以我就想使用类来封装这多个操作数组的方法。将来在需要对数组进行操作的时候,就直接去找封装了数组操作的类,然后调用类中的方法即可。–这种思想就是面向对象思想的编程方式。 - 简单说: 要做一件事情的时候,先找人问他会不会,不会,滚蛋 会 好你来。
2,面向对象之前有面向过程
- 面向过程:
回想一下我们这几次课的内容,我们要完成一个需求,先分析我们要干什么。然后分析我们应该怎么干?最后是我们根据我们的分析过程一步步自己完成了代码的编写。最终实现了所谓的功能。
具体的每一个步骤都是我们自己完成的。最后这些个步骤结合到一起相互协作,完成了我们的需求。每一步我们都是参与者,我们需要面对每一个过程和步骤。这其实就是面向过程的直接体现。 - 面向过程开发:就是我们要面向具体每一个步骤,完成每一个步骤,最后完成需求
- 面向过程的代表语言:C
- 面向过程是面向对象的基础。面向对象是基于面向过程的。
3,当需求比较单一,或者比较简单的时候,我们一步步自己去实现觉得也没问题。
但是随着需求的不断更改和增加。功能的增多。这个时候你再去面对每一个步骤就会非常麻烦了。这个时候我们就需要考虑封装,根据功能的不同进行不同的封装把功能类似的封装到一起。最后整个结构就会变得非常清晰了。用的时候找对应的类就可以了。这就是面向对象思想。
4,面向对象思想:
- 面向对象是基于面向过程的。
- 面向过程:强调的是每一个步骤。
- 面向对象:强调的是对象,然后由对象调用功能。
5,特点:
- 把复杂的事情简单话了。
- 把我们从执行者变成了指挥者。
- 更加符合我们现代人的思想习惯的思想。
2 面向对象开发、设计、特征
1. 面向对象开发、设计、特征
- 面向对象开发:
就是不断的创建对象,使用对象,指挥对象做事情。 - 面向对象的设计:
其实就是管理和维护对象之间的关系。 - 面向对象的三大特征
封装 继承 多态
2. 类和对象之间的关系
- 我们学习编程,就是为了模拟现实的事物。实现所谓的信息化。
比如:现在超市的计费系统, 银行的业务系统。。。。 - 我们如何表示一个现实世界的事物呢?
现实事物有什么东西?
行为:就是事物的功能
属性:就是事物的信息
手机 学生 - 我们java语言最基本的单位是类,所以我们就应该把事物用一个类来体现。
类:
成员方法:
成员变量:
我们就找到了类和事物之间的对应关系了
学生:
姓名,年龄。。。
学习,吃饭。。。
学生类:
成员变量:
String name; int age;
成员方法:
学习() 吃饭() - 类:是一组相关属性和行为的集合。是一个抽象概念。
- 对象:该类事物的具体的个体。
学生类:
王大牛----对象
3. 类的定义
- 类是封装对象的属性和行为的载体,反过来说具有相同属性和行为的一类实体称为类。
- 定义类就是定义类的成员(成员变量和成员方法)
- 成员变量:和变量的定义格式相同,只是位置不同。定义在类中方法外
- 成员方法:和方法的定义格式相同,只需去掉static
/*
学生事物:
属性:姓名,年龄,性别。。。
行为:学习,吃饭,睡觉。。。
转成对应的类
学生类:
成员变量:姓名,年龄,性别。。。
成员方法:学习,吃饭,睡觉。。。
*/
class Student{
//定义成员变量
String name;
int age;
String gender;
//定义成员方法
public void study(){
System.out.println("学生要学习");
}
public void eat(){
System.out.println("学生要吃饭");
}
public void sleep(){
System.out.println("学生要睡觉");
}
}
4. 如何使用??
- 要使用具体的个体来使用
- 如何获取具体的个体,需要创建对象
-创建对象的格式
类名 对象名 = new 类名(); - 如何使用成员变量?
对象名.变量名 - 如何使用成员方法?
对象名.方法名(…);
/*
在一个java文件中写了2个类,一个测试类,一个基本类
注意:文件名要和测试类名一致。这种方式不建议。
建议一个文件中只写一个类。
*/
class Demo1{
public static void main(String[] args){
//创建对象
Student s = new Student();
//使用
System.out.println(s.name);
System.out.println(s.age);
System.out.println(s.gender);
s.study();
s.eat();
s.sleep();
}
}
/*
学生事物:
属性:姓名,年龄,性别。。。
行为:学习,吃饭,睡觉。。。
转成对应的类
学生类:
成员变量:姓名,年龄,性别。。。
成员方法:学习,吃饭,睡觉。。。
*/
class Student{
//定义成员变量
String name;
int age;
String gender;
//定义成员方法
public void study(){
System.out.println("学生要学习。。");
}
public void eat(){
System.out.println("学生要吃饭。。");
}
public void sleep(){
System.out.println("学生要睡觉。。");
}
}
练习(定义一个手机类)
class Demo2{
public static void main(String[] args){
//创建对象
Phone p = new Phone();
//输出成员变量
System.out.println(p.brand);
System.out.println(p.price);
System.out.println(p.color);
//调用成员方法
p.call("主席");
p.sendMessage("老范");
p.playGame();
//默认值没有意义,重新给成员变量赋值
p.brand = "三星s20";
p.price = 6666;
p.color = "黑色";
System.out.println(p.brand);
System.out.println(p.price);
System.out.println(p.color);
p.call("主席");
p.sendMessage("老范");
p.playGame();
}
}
class Phone{
//品牌
String brand;
//价格
double price;
//颜色
String color;
//打电话
public void call(String name){
System.out.println("给"+name+"打电话。");
}
//发信息
public void sendMessage(String name){
System.out.println("给"+name+"发短信。");
}
//玩游戏
public void playGame(){
System.out.println("打王者。");
}
}
5. 对象内存图
- 一个对象(对象的创建过程)
class Demo3{
public static void main(String[] args){
//创建对象
Phone p = new Phone();
System.out.println(p);
//输出成员变量
System.out.println(p.brand);
System.out.println(p.price);
System.out.println(p.color);
//调用成员方法
p.call("主席");
p.sendMessage("老范");
p.playGame();
//默认值没有意义,重新给成员变量赋值
p.brand = "三星s20";
p.price = 6666;
p.color = "黑色";
System.out.println(p.brand);
System.out.println(p.price);
System.out.println(p.color);
p.call("主席");
p.sendMessage("老范");
p.playGame();
}
}
- 两个对象(方法共用)
class Demo4{
public static void main(String[] args){
Phone p1 = new Phone();
p1.brand = "三星s20";
p1.price = 6666;
p1.color = "黑色";
System.out.println(p1.brand+","+p1.price+","+p1.color);
p1.call("主席");
p1.sendMessage("老范");
p1.playGame();
Phone p2 = new Phone();
p2.brand = "苹果12";
p2.price = 8888;
p2.color = "白色";
System.out.println(p2.brand+","+p2.price+","+p2.color);
p2.call("主席");
p2.sendMessage("老范");
p2.playGame();
}
}
- 三个对象(其中两个引用指向同一个对象)
class Demo5{
public static void main(String[] args){
Phone p1 = new Phone();
p1.brand = "三星s20";
p1.price = 6666;
p1.color = "黑色";
System.out.println(p1.brand+","+p1.price+","+p1.color);
Phone p2 = new Phone();
p2.brand = "苹果12";
p2.price = 8888;
p2.color = "白色";
System.out.println(p2.brand+","+p2.price+","+p2.color);
Phone p3 = p1;
System.out.println(p3.brand+","+p3.price+","+p3.color);
p3.brand = "华为mate40";
p3.price = 10000;
p3.color = "深海蓝";
System.out.println(p1.brand+","+p1.price+","+p1.color);
System.out.println(p2.brand+","+p2.price+","+p2.color);
System.out.println(p3.brand+","+p3.price+","+p3.color);
}
}
6. 成员变量和局部变量的区别
- 在类中的位置不同
成员变量:类中方法外
局部变量:方法内或方法声明上 - 在内存上的位置不同
成员变量:堆中
局部变量:栈中 - 生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失 - 初始值不同
成员变量:有系统给的默认值
局部变量:没有默认值,必须定义完赋值后才能使用
- 注意:
局部变量的名字可以跟成员变量的名字一样,在方法中使用时,采用的是就近原则。
class Aaa{
//成员变量
int num = 5;
public void show(){
//局部变量
//int num = 55;
int num2 = 44;
System.out.println("num="+num);
System.out.println("num2="+num2);
}
}
class Demo6{
public static void main(String[] args){
Aaa a = new Aaa();
a.show();
}
}
7. 形式参数问题
如果我们看到一个方法的形式参数是一个类类型(引用类型),这里实际上要的是该类的具体的对象。
class Demo7{
public static void main(String[] args){
//测试Stu类中的方法
Stu s = new Stu();
s.study();
s.eat();
//测试StuDemo类中的show方法
StuDemo sd = new StuDemo();
//int i = 5;
Stu ss = new Stu();//地址值
sd.show(ss);//Stu s = ss;
}
}
class StuDemo{
/*
如果我们看到一个方法的形式参数是一个类类型(引用类型)
这里实际上要的是该类的具体的对象。只有具体的对象才能掉方法
调用的时候,实际上是把main方法中的ss的地址值传递给了show方法
的局部变量s
*/
public void show(Stu s){//Stu s = ss; Stu s = new Stu(); 地址值
s.eat();
s.study();
}
}
class Stu{
//定义成员变量
String name;
int age;
String gender;
//定义成员方法
public void study(){
System.out.println("学生要学习。。");
}
public void eat(){
System.out.println("学生要吃饭。。");
}
public void sleep(){
System.out.println("学生要睡觉。。");
}
}
8. 匿名对象
- 匿名对象:
就是没有名字的对象,是对象的简化表示形式。
Stu s = new Stu(); int i = 5;
new Stu();这就是匿名对象 - 应用:
调用方法,当方法只需要调用一次的时候。
当调用多次的时候,不合适。匿名对象多次掉方法,每次都是一个新的对象。
既然这样它有什么优点码?
有,匿名对象调用完方法之后,就会编程垃圾。可以被回收。
可以当作实际参数区传递
class Demo8{
public static void main(String[] args){
//测试Stu类中的方法
/*Stu s = new Stu();
s.study();
s.study();
s.study();
new Stu().study();
new Stu().study();
new Stu().study();
*/
//测试StuDemo类中的show方法
//StuDemo sd = new StuDemo();
//Stu ss = new Stu();
//sd.show(ss);
//sd.show(new Stu());
new StuDemo().show(new Stu());
}
}
二,封装
1,概述
- 隐藏对象的属性和实现细节。对外提供公有的访问方式。
- 好处:
隐藏对象的属性和实现细节,提供公有的访问方式
提高了安全性。
提高了代码的复用性 - 封装原则:
把不需要对外界提供的内容就隐藏起来。
根据需求提供对应的访问方式。
class Stu{
//定义成员变量
String name;
private int age;
private String gender;
//验证年龄的方法
/*
返回值类型:void
参数列表:int a
*/
public void setAge(int a){
if(a>0 & a<150){
age = a;
}else{
System.out.println("年龄不合法。。。");
}
}
//验证性别的方法
public void setGender(String g){
if(g.equals("男")||g.equals("女")){
gender = g;
}else{
System.out.println("性别不合法。。。");
}
}
//定义成员方法
public void study(){
System.out.println("学生要学习。。");
}
public void eat(){
System.out.println("学生要吃饭。。");
}
public void sleep(){
System.out.println("学生要睡觉。。");
}
//展示所有成员变量值的方法
public void show(){
System.out.println("我叫:"+name+",今年:"+age+"岁,性别:"+gender+",我找对象。");
}
}
/*
我定义了一个Stu类,这里进行测试。
在测试过程中发现问题了:
使用对象名.成员变量给成员变量赋值的时候,可以赋值一些非法数据。
这很明显不合理。
应该是什么样?
在赋值前,先对数据进行判断,判断数据是否合法,合法在赋值。
判断应该写在哪里?
写在Stu中,因为Demo9只是一个测试类。测试类一般只创建对象,调用方法。
写在什么位置?
在成员变量位置不能进行判断。因为判断要用到逻辑语句。
逻辑语句应该写在方法中。所以我们要在Stu类中提供方法
来进行数据的验证。
按照分析,我们定义了验证方法,而且使用方法赋值可以保证数据的正确性。
但是,他可以不适用方法,依然使用以前的方式赋值。照样可以赋值非法数据。
怎么办?应该是强制要求他只能使用验证方法来赋值。怎么强制要求呢?
不用担心,java就给我们提供了一个关键字 private
private:私有的。可以修饰成员变量和成员方法
特点:被private修饰的成员只能在自己所在的类中访问。
其实我到现在为止讲的就是一个封装思想。
封装:隐藏对象的属性和实现细节。对外提供公有的访问方式。
*/
class Demo9{
public static void main(String[] args){
Stu s = new Stu();
s.show();
System.out.println("........................");
//给成员变量赋值
s.name = "马蓉";
//s.age = -38;
//s.gender = "110";
s.show();
System.out.println("........................");
//使用验证方法赋值
//s.setAge(-38);
//s.setGender("人妖");
s.setAge(38);
s.setGender("女");
s.show();
System.out.println("........................");
//谁说你有了验证方法我就必须用,我偏不用。
//s.age = -38;age 在 Stu 中是 private 访问控制
//s.gender = "110"; gender 在 Stu 中是 private 访问控制
//s.show();
//System.out.println("........................");
}
}
2.private关键字
- 一个权限修饰符
- 可以修饰成员变量和成员方法
- 被private修饰的成员只能在自己所在的类中访问。
- 常见应用
把成员变量用private修饰,提供对应的getXxx()和setXxx()方法 - 标准的应用案例
把成员变量用private修饰
提供对应的get和set方法
class Demo{
public static void main(String[] args){
Tea t = new Tea();
//是 private 访问控制
//System.out.println(t.name+","+t.age);
System.out.println(t.getName()+","+t.getAge());
//赋值
//t.name = "aa";
//t.age = 11;
t.setName("默默");
t.setAge(18);
System.out.println(t.getName()+","+t.getAge());
}
}
class Tea{
private String name;
private int age;
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
public void setAge(int a){
age = a;
}
public int getAge(){
return age;
}
//提供其他的成员方法,吃饭,睡觉。。。。
}
3. this关键字
我们之前说过名字要见名知意,很明显我们set方法没有知意,然后我们为了做到见名知意。我们把名字改了,局部变量名和成员变量名一致。使用的时候采用的是就近原则,所以最后相当于是把局部变量的值又赋值给了局部变量。 没有赋值到成员变量上。
之前给成员变量赋值 对象名.成员变量名 = 赋值;
this:是当前类的对象的引用。
简单说,当前是类的哪个具体对象调用我,方法内部的this就表示哪个对象。this解决了 局部变量和成员变量同名的问题。
class Tea{
private String name;
private int age;
public void setName(String name){
//对象名.name = name;
//在这里谁能够表示哪个对象呢?为了解决这个问题java
//就给我们提供了一个关键字 this
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
//提供其他的成员方法,吃饭,睡觉。。。。
}
class Demo{
public static void main(String[] args){
Tea t = new Tea();
//是 private 访问控制
//System.out.println(t.name+","+t.age);
System.out.println(t.getName()+","+t.getAge());
//赋值
//t.name = "aa";
//t.age = 11;
t.setName("默默");
t.setAge(18);
System.out.println(t.getName()+","+t.getAge());
Tea t2 = new Tea();
}
}
- 标准的手机类
class Phones{
private String brand;
private double price;
private String color;
public void setBrand(String brand){
this.brand = brand;
}
public String getBrand(){
return brand;
}
public void setPrice(double price){
this.price = price;
}
public double getPrice(){
return price;
}
public void setColor(String color){
this.color = color;
}
public String getColor(){
return color;
}
}
class Demo9{
public static void main(String[] args){
Phones p = new Phones();
System.out.println(p.getBrand()+","+p.getPrice()+","+p.getColor());
p.setBrand("苹果");
p.setPrice(6799);
p.setColor("黑色");
System.out.println(p.getBrand()+","+p.getPrice()+","+p.getColor());
}
}
4. 构造方法
- 构造方法的作用
给对象的数据进行数据初始化。 - 构造方法的格式
方法名和类名一致
没有返回值类型,连void都没有
没有具体的返回值 - 注意事项在下面写着
如果我们定义类的时候没有定义构造方法,那么系统会自动提供一个无参构造方法。
如果我们定义类的时候定义了构造方法,那么系统就不会在提供构造方法。
假设我们自己提供的是一个带参构造,系统照样不会提供无参构造。这个时候如果我们还想使用无参构造,那么就必须自己定义了。
建议以后在写类的时候都自己给出无参构造。
构造方法也可以重载。
class Teacher{
private String name;
private int age;
public Teacher(){
System.out.println("这是构造方法。。。");
}
//get和set
//其他成员方法
}
class Demo13{
public static void main(String[] args){
Teacher t1 = new Teacher();
Teacher t2 = new Teacher();
}
}
- 给成员变量赋值有2种方式:
setXxx()
构造方法
class Teacher{
private String name;
private int age;
public Teacher(){
System.out.println("这是无参构造方法。。。");
}
public Teacher(String name,int age){
System.out.println("这是带name,age的构造方法。。。");
this.name = name;
this.age = age;
}
public void show(){
System.out.println(name+","+age);
}
//get和set
//其他成员方法
}
class Demo13{
public static void main(String[] args){
Teacher t1 = new Teacher();
t1.show();
Teacher t2 = new Teacher("vv",222);
t2.show();
}
}
5. 类的组成:
成员变量
成员方法
根据返回值:
void类型
非void类型
根据参数:
空参方法
带参方法
构造方法
无参
带参
- 标准的应用案例最终版
私有成员变量
提供对应get和set方法
提供无参和带参方法
其他的成员方法 - 练习:定义一个标准的电脑类,进行测试
- 无参构造+set
- 带参构造
6. 类的初始化方法
Tea t1 = new Tea();
- 加载Tea.class 文件进内存
- 在栈内存中给局部变量 Tea t1 开辟空间
- 在堆内存中给对象开辟空间
- 给对象的成员变量进行默认初始化
给对象的成员变量进行显示初始化
给对象的成员变量进行构造初始化 - 对象初始化完成,把对象的地址赋值给栈中的变量
class Dog{
private String name = "汪汪";//显示初始化
private int age = 1;
public Dog(){
//name = "小黄";
//age = 2;
}
public void show(){
System.out.println(name+","+age);
}
}
class Demo4{
public static void main(String[] args){
Dog d = new Dog();
d.show();
}
}
7.变量什么时候定义成成员变量
如果这个变量是描述这个类的信息的,就应该定义成成员变量,否则就是局部变量。
/*
写一个求和方法
*/
class Demo5{
public static void main(String[] args){
int a = 5;
int b = 6;
MySum ms = new MySum();
//int sum = ms.sum(a,b);
//System.out.println(sum);
ms.a = a;
ms.b = b;
int sum = ms.sum();
System.out.println(sum);
}
}
/*
class MySum{
public int sum(int a,int b){
return a+b;
}
}
*/
/*
这个方式满足需求,我们刚好学习了面向对象思想。
那我就想能不能用面向对象的思想来实现呢?
如果可以,把a和b定义成成员变量
*/
class MySum{
int a;
int b;
public int sum(){
return a+b;
}
}
/*
这样可以,而且感觉好像还符合面向对象思想。
但是这样不合适?为啥呢?
因为我们说过类是一组相关属性和行为的集合。
类是通过现实事物转换而来的。
类中的成员变量应该是 事物的属性
类中的成员方法应该是 事物的行为
类中成员变量应该是描述类的信息的
*/
8. 练习:定义一个矩形类,提供求周长和面积的方法,然后测试
class Rectangle{
int length;
int width;
//求周长的方法
public static int getCir(int length,int width){
return 2*(length+width);
}
//求面积的方法
public static int getArea(int length,int width){
return length*width;
}
}
import java.util.Scanner;
class Test1{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入矩形的长:");
int length = sc.nextInt();
System.out.println("请输入矩形的宽:");
int width = sc.nextInt();
int cir = Rectangle.getCir(length,width);
System.out.println("矩形的周长是"+cir);
int area = Rectangle.getArea(length,width);
System.out.println("矩形的面积是"+area);
}
}
static关键字
- 可以修饰成员(成员变量和成员方法)
- 特点:
被static修饰的成员变量被类的所有对象共享。
也是我们判断要不要用static修饰的标准。
随着类的加载而加载
优先于对象存在
可以通过类名调用,依然也可以通过对象名调用
推荐使用类名调用
/*
不同的人姓名,年龄不一样,这个没问题。
但是,我现在找的几个人都是岛国的。他们的地址一样。
一样的地址,每次创建对象的时候都要在堆内存中开辟空间保存同样的值。
就觉得有点浪费内存。怎么办?
针对这种情况,多个对象有一样的成员变量值的情况
为了提高内存的利用率。java就给我们提供了一个关键字 static
*/
class Demo6{
public static void main(String[] args){
//造女朋友
Person p1 = new Person("中山忍",18,"日本");
p1.show();
//Person p2 = new Person("苍老师",38,"岛国");
//p2.show();
//Person p3 = new Person("玛丽",22,"岛国");
//p3.show();
Person p2 = new Person("苍老师",38,"岛国");
p2.show();
Person p3 = new Person("玛丽",22);
p3.show();
}
}
class Person{
String name;
int age;
//String address;
static String address;
public Person(){}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public Person(String name,int age,String address){
this.name = name;
this.age = age;
this.address = address;
}
public void show(){
System.out.println("我叫:"+name+",今年"+age+",岁,来自:"+address+",我单身,约吗?");
}
}
- 注意事项:
在静态方法中不能使用this关键字
静态方法可以通过类名调用,可以不创建对象,而this关键字表示的是调方法的那个具体的对象
静态的方法中只能访问静态的成员变量和成员方法
非静态方法:
成员变量:可以是静态的,也可以是非静态的
成员方法:可以是静态的,也可以是非静态的
静态方法:
成员变量:只能访问静态的
成员方法:只能访问静态的
简单说:静态只能访问静态 - 静态变量和成员变量的区别:
1.所属不同
成员变量:对象, 也成为实例变量
静态成员变量:属于类, 也称为类变量
2.内存位置不同
成员变量:堆
静态成员变量:方法区的静态区
3.出现时间不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
静态成员变量:随着类的加载而加载,随着类的消失而消失
4.调用不同
成员变量:只能使用对象名访问
静态成员变量:可以使用对象名,也可以使用类名 - main方法为什么是静态的
public static void main(String[] args){}
-String[] args 是一个字符串数组,这个东西是早期用来接收键盘输入的
class Demo2{
public static void main(String[] args){
//Tea t = new Tea();
//t.show();
//t.fun();
//System.out.println(args);
//System.out.println(args.length);
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
}
}