面向对象编程

image

一、面向过程与面向对象

  1. 面向过程(POP) 与 面向对象(OOP)

面向对象:Object Oriented Programming
面向过程:Procedure Oriented Programming
image

2.面向对象的三大特征

封装(Encapsulation)
继承(Inheritance)
多态(Polymorphism)

3.面向对象的思想概述

  • 程序员从面向过程的执行者转化成了面向对象的指挥者
  • 面向对象分析方法分析问题的思路和步骤:
    • 根据问题需要,选择问题所针对的现实世界中的实体。
    • 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
    • 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
    • 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
import java.io.IOException;
 
/*

 * 一、Java面向对象学习的三条主线
 *  1、Java类及类的成员:属性、方法、构造器、代码块、内部类
 *  2、面向对象的三大特性:封装性、继承性、多态性、(抽象性)
 *  3、其它关键字:this、super、static、final、abstract、interface、package、import等
 *
 *  大处着眼,小处着手
 *
 * 二、人把大象装入冰箱
 *  1、面向过程:强调的是功能和行为,以函数作为最小单位,考虑怎么做
 *  (1)打开冰箱门
 *  (2)抬起大象,塞进冰箱
 *  (3)关闭冰箱门
 *
 *  2、面向对象:强调具备了功能的对象,以 类/对象 为 最小单位,考虑谁来做
 *
 *  人{
 *      打开(冰箱){
 *        冰箱.开门();
 *      }
 *      抬起(大象){
 *          大象.进入冰箱();
 *      }
 *      关闭(冰箱){
 *          冰箱.关门();
 *      }
 *  }
 *
 *  冰箱{
 *      开门(){}
 *      关门(){}
 *  }
 *
 * 大象{
 *      进入(冰箱){}
 * }
 *
 * 三、面向对象的两个要素
 *  类:对一类事务的描述,是抽象的、概念上的定义。
 *  对象:是实际存在的该类事物的个体,因而也称为实例(instance)。
 *  面向对象程序的设计重点就是类的设计
 *  设计类,就是设计类的成员
 */
public class OOPTest {
    public static void main(String[] args) throws IOException {
 
    }
}
 

二、Java基本元素:类和对象

  • 类(Class)和对象(Object)是面向对象的核心概念。
  • 类是对一类事物的描述,是抽象的、概念上的定义
  • 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
  • “万事万物皆对象”面向对象程序设计的重点是类的设计
  • 类的设计,其实就是类的成员的设计

2.Java类及类的成员

常见的类的成员有:

  • 属 性:对应类中的成员变量
  • 行 为:对应类中的成员方法
    Field = 属性 = 成员变量,Method = (成员)方法 = 函数
    image

(1)类的成员构成 version 1.0
image
(2)类的成员构成 verson 2.0
image
(3)类的语法格式
image
(4)创建Java自定义类

	//1.创建类,设计类的成员
	public class Oop1 {
		//属性
		String name;
		int age;
		boolean inMale;

		//方法
		public void eat(){
			System.out.println("人可以吃饭");
		}
		public void sleep(){
			System.out.println("人可以睡觉");
		}
		public void talk(String language){
			System.out.println("人可以说话,使用的语言是:" + language);
		}
	}

步骤:

定义类(考虑修饰符、类名)

编写类的属性(考虑修饰符、属性类型、属性名、初始化值)

编写类的方法(考虑修饰符、返回值类型、方法名、形参等)

三、对象的创建和使用
image

/**
 * 一、设计类,其实就是设计类的成员
 *  属性 = 成员变量 = filed = 域、字段
 *  方法 = 成员方法 = 函数 = method
 *  创建类的对象 = 类的实例化 = 实例化类
 *
 * 二、类和对象的使用(面向对象思想的落地实现)
 *  1、创建类,设计类的成员
 *  2、创建类的对象
 *  3、通过 “对象.属性” 或 “对象.方法” 调用对象的结构
 *
 * 三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
 *     意味着:我们修改一个对象的属性a,则不影响另外一个对象属性a的值
 *
 * 四、对象的内存解析
 
 
 */
 public class PeopleTest {
    public static void main (String[] args){
        //2.创建People类的对象
        People people = new People();
        //3.调用对象的结构:属性、方法
        //调用属性:"对象.属性"
        people.name = "张三";
        people.isMale = true;
        System.out.println(people.name);
        //调用方法:"对象.方法"
        people.eat();
        people.sleep();
        people.talk("Chinese");

        People people1 = new People();
        System.out.println(people1.name);
        System.out.println(people1.isMale);
        //将people保存的对象地址值赋给people2,导致people和people2指向了堆空间中的同一个对象的实体
        People people2 = people;
        System.out.println(people2.name);//张三

        people2.age = 10;
        System.out.println(people2.age);//10

    }
}

//1.创建类,设计类的成员
class People {
    //属性
    String name;
    int age;
    boolean isMale;
    //方法
    public void eat(){
        System.out.println("人可以吃饭");
    }
    public void sleep(){
        System.out.println("人可以睡觉");
    }
    public void talk(String language){
        System.out.println("人可以说话。使用的语言是:" + language);
    }
}

1.创建对象语法
类名 对象名 = new 类名();

	//2、创建People类的对象
	People people = new People();

2.使用
“对象名.对象成员”的方式访问对象成员(包括属性和方法)

	//3、调用对象的结构:属性、方法
	//调用属性:“对象.属性”
	people.name = "张三";
	people.isMale = true;
	System.out.println(people.name);

	//调用方法:“对象.方法”
	people.eat();
	people.sleep();
	people.talk("Chinese");

3.Java中类与对象
image
说明:如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰。

//2、创建People类的对象
People people = new People();
people.name = "张三";
people.isMale = true;
System.out.println(people.name);
 
People people1 = new People();
System.out.println(people1.name);
System.out.println(people1.isMale);
 
//将people保存的对象地址值赋给people1,导致people和people1指向了堆空间中的同一个对象的实体。
People people2 = people;
System.out.println(people2.name);//张三
 
people2.age = 10;
System.out.println(people.age);//10

类的访问机制:
在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。(例外:static方法访问非static,编译不通过。)

在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。

对象的产生

Person p1 = new Person();//执行完后的内存状态。其中类定义如下:
class Person{
    int age;
    void shout(){
        System.out.println(“oh,my god! 	I am ” + age);
    }
}

image
对象的使用

class PersonTest{
    public static void main(String[] args) { //程序运行的内存布局如下图
        Person p1 = new Person();
        Person p2 =  new Person();
        p1.age = -30;
        p1.shout();
        p2.shout();
    }
}

image

对象的生命周期
image
待学习
内存解析
image

  • 堆(Heap),此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
  • 通常所说的栈(Stack),是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char 、 short 、 int 、 float 、 long 、double)、对象引用(reference类型,它不等同于对象本身,是对象在堆内存的首地址)。 方法执行完,自动释放。
  • 方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
Person p1 = new Person();
p1.name = "Tom";
p1.isMale = true;
Person p2 = new Person();
sysout(p2.name);//null
Person p3 = p1;
p3.age = 10;

image

根据代码,画出内存图

class Car{
    String color = "red";
    int num = 4;
    void show(){
        System.out.println("color="+color+"..num="+num);
    }
}
class CarTest {
    public static void main(String[] args) {
        Car c1 = new Car(); //建立对象c1
        Car c2 = new Car(); //建立对象c2
        c1.color = "blue"; //对对象的属性进行修改
        c1.show(); //使用对象的方法
        c2.show();
    } }

image

匿名对象

  • 我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。
  • 如:new Person().shout();
  • 使用情况
  • 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
  • 我们经常将匿名对象作为实参传递给一个方法调用。
 
/**
 *  1、理解:我们创建的对象。没有显示的赋值给一个变量名,即为匿名对象
 *  2、特征:匿名对象只能调用一次
 *  3、使用:
 */
public class Demo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        System.out.println(phone);
        phone.sendEmail();
        phone.playGame();
 
        //匿名对象
        new Phone().playGame();
 
        new Phone().price = 1999;
        new Phone().showPrice();// 0.0
 
        //使用情景
        PhoneMall phoneMall = new PhoneMall();
        phoneMall.show(new Phone());
 
    }
}
 
class PhoneMall{
    public void show(Phone phone){
        phone.sendEmail();
        phone.playGame();
    }
}
 
class Phone{
    double price;
 
    public void sendEmail(){
        System.out.println("发送邮件");
    }
 
    public void playGame(){
        System.out.println("玩游戏");
    }
 
    public void showPrice(){
        System.out.println("手机的价格为:" + price);
    }
}

四、类的成员之一:属性
1.语法格式
修饰符 数据类型 属性名 = 初始化值 ;

  • 说明1: 修饰符:常用的权限修饰符有:private、缺省、protected、public
  • 其他修饰符:static、final (暂不考虑)
  • 说明2:数据类型:任何基本数据类型(如int、Boolean) 或 任何引用数据类型。
  • 说明3:属性名: 属于标识符,符合命名规则和规范即可。

2.变量的分类:成员变量与局部变量

在方法体外,类体内声明的变量称为成员变量。
在方法体内部声明的变量称为局部变量。
image

成员变量(属性)和局部变量的区别
image

成员变量vs局部变量的内存位置

/**
 *  类中属性的使用
 *      成员变量 vs 局部变量
 *      1、相同点:
 *          (1)定义变量的格式:数据类型 变量名 = 变量值
 *          (2)先声明,后使用
 *          (3)变量都有其对应的作用域
 *      2、不同点
 *          (1)在类中声明的位置不同
 *              属性:直接定义在类的一对 {}
 *              局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
 *
 *          (2)关于权限修饰符不同
 *              属性:可以在声明属性时,指定其权限,使用权限修饰符
 *                  常用的权限修饰符:private、public、缺省、protected -->封装性
 *                  目前:大家声明属性时,都使用缺省就可以了
 *              局部变量:不可以使用权限修饰符
 *
 *           (3)默认初始化值的情况
 *              属性:类的属性,根据其类型,都有初始化值
 *                  整形(byte、short、int、long): 0
 *                  浮点型(float、double):0.0
 *                  字符型(char):0 或者 '/u0000'
 *                  布尔型(boolean):false
 *                  引用数据类型(类、数组、接口):null
 *              局部变量:没有默认初始化值
 *                    意味着我们在调用局部变量之前,一定要显示赋值
 *                    特别的:形参在调用时,我们赋值即可
 *
 *              (4)在内存中加载的位置
 *                  属性:加载到堆空间中(非static)
 *                  局部变量:加载到栈空间中
 *
 *
 */
 
public class UserTest {
    public static void main(String[] args) {
        User user = new User();
        System.out.println(user.name);
        System.out.println(user.age);
        System.out.println(user.isMale);
        
        user.talk("中文");
        user.eat();
    }
}

class User {
    //属性(成员变量)
    String name;
    public int age;
    boolean isMale;
    
    public void talk(String language){//language:形参,也是局部变量
        System.out.println("我们使用" + language + "进行交谈");
    }
    public void eat(){
        String food = "烙饼";//局部变量
        System.out.println("北方人喜欢吃 " + food);
    }
}

image

对象属性的默认初始化赋值

当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。除了基本数据类型之外的变量类型都是引用类型,如上面的Person及前面讲过的数组。
image

五、类的成员之二:方法

/**
 * @author: huxingxin
 * @date: 2022/11/27 21:33:41
 * @description:
 *  类中方法的声明和使用
 *
 *  方法:描述类应该具有的功能
 *  比如:Math类:sqrt()、random()
 *        Scanner类:next()
 *        Arrays类:sort()、binarySearch()、toString()、equals()
 *
 *  1、举例
 *     public void eat(){}
 *     public void sleep(int hour){}
 *     public String getName(){}
 *     public String getNation(String nation){}
 *
 *  2、方法的声明:权限修饰符 返回值类型 方法名(形参列表){
 *                     方法体
 *                 }
 *
 *     static、final、abstract 来修饰的方法,后面再讲
 *
 *  3、说明
 *      (1)关于权限修饰符:
 *            Java中规定的四种权限修饰符:private、public、缺省、protected --> 封装性再细说
 *
 *      (2)返回值类型:有返回值类型 vs 没有返回值类型
 *           (2.1)  如果有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或者常量,"return 数据"。
 *
 *                    如果没有返回值,则方法声明时,使用void来表示,通常,没有返回值的方法中就不使用return,如果使用的话,只能 "return;",
 *                 表示结束此方法的意思。
 *
 *                     return后不可以声明表达式
 *
 *            (2.2)我们定义方法该不该有返回值
 *                  题目要求
 *                  凭经验:具体问题 具体分析
 *      (3)方法名:属于标识符,遵循标识符的规则和规范,见名知意
 *
 *      (4)形参列表:方法可以声明0个 1个 或者多个形参
 *         (4.1) 格式:数据类型1 形参1, 数据类型2 形参2, ...
 *        (4.2)我们定义方法时,该不该定义形参?
 *              题目要求
 *              凭经验:具体问题 具体分析
 *
 *       (5)方法体:方法功能的实现
 *
 *  4、return关键字的使用
 *      使用范围:使用在方法体中
 *      作用:
 *          结束方法
 *          针对于有返回值类型的方法,使用 "return 数据;" 返回所要的数据
 *      注意点:return关键字后面不可以声明执行语句
 *
 *  5、方法的使用:可以当前类的属性或方法
 *      特殊的:方法A中又调用了方法A:递归
 *     方法中不可以定义方法
 */
 
public class CustomerTest {
    public static void main(String[] args) {
        Customer customer = new Customer();
        customer.sleep(9);
    }
}

class Customer {
    //属性
    String name;
    int age;
    boolean isMale;

    //方法
    public void eat(){
        System.out.println("客户吃饭");
        return;
        //return后不可以声明表达式
        //System.out.println();
    }

    public void sleep(int hour){
        System.out.println("休息了" + hour + "个小时");
        eat();
    }
    public String getName() {
        return name;
    }
    public String getNation(String nation){
        String info = "我的国籍是" + nation;
        return info;
    }
}

1.什么是方法(method、函数)

  • 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。

  • 将功能封装为方法的目的是,可以实现代码重用,简化代码。

  • Java里的方法不能独立存在,所有的方法必须定义在类里。

public class Person{
    private int age;
    public int getAge() { //声明方法getAge()
        return age; 
    }
    public void setAge(int i) { //声明方法setAge
        age = i; //将参数i的值赋给类的成员变量age
    }
}

2.方法的声明格式

修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){
    方法体程序代码
    return 返回值;
}
  • 修饰符:public,缺省,private, protected等
  • 返回值类型:
  • 没有返回值:void。
  • 有返回值,声明出返回值的类型。与方法体中“return 返回值”搭配使用
  • 方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意”
  • 形参列表:可以包含零个,一个或多个参数。多个参数时,中间用“,”隔开
  • 返回值:方法在执行完毕后返还给调用它的程序的数据

3.方法的分类
按照是否有形参及返回值
image

4.方法的调用
方法通过方法名被调用,且只有被调用才会执行。
方法调用的过程分析
image

  • 注 意:

  • 方法被调用一次,就会执行一次

  • 没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可以不必使用return语句。如果使用,仅用来结束方法。

  • 定义方法时,方法的结果应该返回给调用者,交由调用者处理。

  • 方法中只能调用方法或属性,不可以在方法内部定义方法。

六、练习
1.练习1
编写教师类和学生类,并通过测试类创建对象进行测试
image

public class Test {
    public static void main(String[] args) {
        //创建对象 进行测试
        Student student = new Student();
        student.name = "张三" ;
        student.age = 20;
        student.major = "计算机";
        student.interests = "编程";
        String info = student.say();
        System.out.println(info);

        Teacher teacher = new Teacher();
        teacher.name = "李四";
        teacher.age = 30;
        teacher.teachAge = 7;
        teacher.course = "计算机";
        teacher.say();

    }
}

//创建Student类
class Student{
    String name;
    int age;
    String major;
    String interests;

    public String say(){
        return "姓名:" + name + "年龄:" + age + "专业:" + major + "兴趣:" + interests;
    }
}
//创建Teacher类
class Teacher{
    String name;
    int age;
    int teachAge;
    String course;

    public void say(){
        System.out.println("姓名:" + name + " 年龄:" + age + " 教学年龄:" + teachAge + " 课程:" + course);
    }
}

2.练习2
(1)创建Person类的对象,设置该对象的name、age和sex属性,调用study方法,输出字符串“studying”,调用showAge()方法显示age值,

调用addAge()方法给对象的age属性值增加2岁。

(2)创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系。

public class Test2 {
/*    (1)创建Person类的对象,设置该对象的name、age和sex属性,调用study方法,输出字符串“studying”,调用showAge()方法显示age值,调用addAge()方法给对象的age属性值增加2岁。
      (2)创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系。*/
    
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "张三";
        person.age = 30;
        person.sex = 0;

        person.study();
        person.showAge();
        int age = person.addAge(2);
        System.out.println("age = " + age);
    }
}

class Person{
    String name;
    int age;
    int sex;

    public void study(){
        System.out.println("studying");
    }

    public void showAge(){
        System.out.println("age:" + age);
    }
    public int addAge(int number){
        return age += number;
    }
}

3.练习3

/*
 * @description: 利用面向对象的编程方法,设计类Circle计算圆的面积。
 */
public class Test3 {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.radius = 1.2;
        double area = circle.getArea();
        System.out.println("Area is: " + area);
    }
}

class Circle{
    double radius;

    //计算圆的面积
    public double getArea() {
        return Math.PI * Math.pow(radius, 2);
    }
}

对象数组的内存解析
引用数据类型的变量,只能存储两类值: null 和 地址值(包含变量的数据类型)
image

六、再谈方法
1.方法的重载(overload)

public class OverloadDemo {
    public static void main(String[] args) {
        OverloadDemo overloadDemo = new OverloadDemo();
        overloadDemo.getSum(1,2);
    }

    //如下四个方法都构成重载
    public void getSum(int i , int j){}
    public void getSum(double i , double j){}
    public void getSum(String s , int i){}
    public void getSum(int i , String s){}
    //    public int getSum(int i, int j){}
    //    public void getSum(int m, int n){}
    //    private void getSum(int i, int j){}
}

重载的概念
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。

重载的特点:
与返回值类型无关,只看参数列表,且参数列表必须不同(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。

重载示例:

//返回两个整数的和
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;}
public class PrintStream {
    public static void print(int i) {……}
    public static void print(float f) {……}
    public static void print(String s) {……}
    public static void main(String[] args) {
        print(3);
        print(1.2f);
        print("hello!");
    }
}

使用重载方法,可以为编程带来方便。
例如,System.out.println()方法就是典型的重载方法,其内部的声明形式如下

public void println(byte x)
public void println(short x)
public void println(int x)
public void println(long x)
public void println(float x)
public void println(double x)
public void println(char x)
public void println(double x)
public void println()
……

重载练习

public class OverloadTest {
    public static void main(String[] args) {
        OverloadTest overloadTest = new OverloadTest();
        overloadTest.oML(4);
        overloadTest.oML(3, 4);
        overloadTest.oML("Hello Java");
 
        overloadTest.max(10, 20);
        overloadTest.max(30.0, 25.0);
        overloadTest.max(20.1, 20.1, 20.1);
    }
 
 
    /*
    2.编写程序,定义三个重载方法并调用。方法名为mOL。
        三个方法分别接收一个int参数、两个int参数、一个字符串参数。分别 执行平方运算并输出结果,相乘并输出结果,输出字符串信息。
        在主类的main ()方法中分别用参数区别调用三个方法。
 
    3.定义三个重载方法max(),第一个方法求两个int值中的最大值,第二个方法求两个double值中的最大值,第三个方法求三个double值中的最大值,
    并分别调用三个方法。
     */
 
    public void oML(int i){
        System.out.println(Math.pow(i, 2));
    }
 
    public void oML(int i, int j){
        System.out.println(i * j);
    }
 
    public void oML(String s){
        System.out.println(s);
    }
 
    public void max(int i, int j){
        System.out.println(i > j ? i : j);
    }
 
    public void max(double i, double j){
        System.out.println(i > j ? i : j);
    }
 
    public void max(double i, double j, double k){
        if (i > j && i > k){
            System.out.println(i);
        }else if (j > i && j > k){
            System.out.println(j);
        }else {
            System.out.println(k);
        }
    }
 
}
 

2.可变个数的形参

/**
 * 可变个数形参的方法
 *  1、JDK 5.0 新增的内容
 *  2、具体的使用
 *      可变个数形参的格式:数据类型... 变量名
 *      当调用可变个数形参的方法是,传入的参数个数可以是 0个 1个 2个 3个 ...
 *      可变个数形参的方法与本类中方法名相同,形参不同的方法构成重载
 *      可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载,换句话说,二者不能共存
 *      可变个数形参在方法的形参中,必须声明在末尾
 *      可变个数形参在方法的形参中,最多只能声明一个可变形参
 */
public class Demo {
    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.show("a", "b", "c");
    }
 
 
    //当调用可变个数形参的方法是,传入的参数个数可以是 0个 1个 2个 3个 ...
    public void show(String... str){
       for (int i = 0; i < str.length; i++){
           System.out.println(str[i]);
       }
    }
 
    //可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载,换句话说,二者不能共存
//    public void show(String[] str){} //本质上是一个数组
 
    //可变个数形参在方法的形参中,必须声明在末尾
    public void show(int i, String... str){}
}
 

说明:

  1. 声明格式:方法名(参数的类型名 ...参数名)
  2. 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个
  3. 可变个数形参的方法与同名的方法之间,彼此构成重载
  4. 可变参数方法的使用与方法参数部分使用数组是一致的
  5. 方法的参数部分有可变形参,需要放在形参声明的最后
  6. 在一个方法的形参位置,最多只能声明一个可变个数形参
public void test(String[] msg){
	System.out.println("含字符串数组参数的test方法");
}
public void test1(String book){
	System.out.println"****与可变形参方法构成重载的test1方法****");
}
public void test1(String ... books){
	System.out.println("****形参长度可变的test1方法****");
}
public static void main(String[] args){
    TestOverload to = new TestOverload();
    //下面两次调用将执行第二个test方法
    to.test1();
    to.test1("aa" , "bb");
    //下面将执行第一个test方法
    to.test(new String[]{"aa"});
}

3.方法参数的值传递机制
1.理解变量的赋值 ???

/**
 * 关于变量的赋值
 *      如果变量是基本数据类型,此时赋值的是变量所保存的数据值
 *      如果变量是引用数据类型,此时赋值的是变量所保存的地址值
 */
public class Demo {
    public static void main(String[] args) {
 
        //基本数据类型
        int m = 10;
        int n = m;
        System.out.println("m: " + m + ", n: " + n);
 
        n = 20;
        System.out.println("m: " + m + ", n: " + n);
 
        //引用数据类型
        Order order1 = new Order();
        order1.orderId = 1001;
 
        Order order2 = order1;
        System.out.println("order1.orderId: " + order1.orderId + ", order2.orderId: " + order2.orderId);
 
        order2.orderId = 1002;
        System.out.println("order1.orderId: " + order1.orderId + ", order2.orderId: " + order2.orderId);
 
    }
 
}
 
class Order{
    int orderId;
}
 
  • 方法,必须由其所在类或对象调用才有意义。若方法含有参数:

    • 形参:方法声明时的参数
    • 实参:方法调用时实际传给形参的参数值-
  • Java的实参值如何传入方法呢?

  • Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。

    • 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
    • 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参

2.基本数据类型的参数传递

public static void main(String[] args) {
    int x = 5;
    System.out.println("修改之前x = " + x);// 5
    // x是实参
    change(x);
    System.out.println("修改之后x = " + x);// 5
}
public static void change(int x) {
    System.out.println("change:修改之前x = " + x);
    x = 3;
    System.out.println("change:修改之后x = " + x);
}

image

3.引用数据类型的参数传递

public class Test{
    public static void main(String[] args) {
        Person obj = new Person();
        obj.age = 5;
        System.out.println("修改之前age = " + obj.age);// 5
        // x是实参
        change(obj);
        System.out.println("修改之后age = " + obj.age);// 5
    }
    public static void change(Person obj) {
        obj = new Person();
        System.out.println("change:修改之前age = " + obj.age);
        obj.age = 3;
        System.out.println("change:修改之后age = " + obj.age);
    }
}
 
//其中Person类定义为:
class Person{
int age; 
}

image

import java.util.Arrays;
 
/**
 * 方法的形参的传递机制: 值传递
 *      形参:方法定义时,声明的小括号内的参数
 *      实参:方法调用时,实际传递给参数的数据
 *
 *  参数传递机制:
 *      如果参数是基本数据类型,此时实参赋值给形参的是,实参真实存储的数据值。
 *      如果参数是引用数据类型,此时实参赋值给形参的是,实参存储数据的地址值。
 *
 *
 */
public class TransferTest {
    public static void main(String[] args) {
        int m = 10;
        int n = 20;
        System.out.println("m: " + m + ", n: " + n);
 
        //基本数据类型
        TransferTest transferTest = new TransferTest();
        transferTest.swap(m, n);
        System.out.println("m: " + m + ", n: " + n);
 
        //引用数据类型
        Data data = new Data();
        System.out.println("data.m: " + data.m + ", data.n: " + data.n);
        transferTest.swap(data);
        System.out.println("data.m: " + data.m + ", data.n: " + data.n);
 
        //冒泡排序
        int[] arr = {1, 33, 45, 32, 12, 22, 7, -78, 9};
        for (int i = 0; i < arr.length - 1; i++){
            for (int j = 0; j < arr.length - 1 -i; j++){
                if (arr[j] > arr[j + 1]){
//                    int temp = arr[j];
//                    arr[j] = arr[j + 1];
//                    arr[j + 1] = temp;
 
                    //错误的
//                    transferTest.swap(arr[j], arr[j+1]);
 
                    //正确的
                    transferTest.swap(arr, j, j + 1);
 
                }
            }
        }
        System.out.println(Arrays.toString(arr));
 
 
    }
 
    public void swap(int m, int n){
        int temp;
        temp = m;
        m = n;
        n = temp;
    }
 
    public void swap(Data data){
        int temp = data.m;
        data.m = data.n;
        data.n = temp;
    }
 
    /**
     * 将两个数值的交换 封装成一个方法
     * @param arr 数组
     * @param i 数组下标
     * @param j 数组下标
     */
    public void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
 
 
}
 
class Data{
    int m = 10;
    int n = 20;
}
 

4.练习
。。。

七、OOP特征一:封装与隐藏

  • 为什么需要封装?封装的作用和含义?
    • 我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
    • 我要开车,…
  • 我们程序设计追求“高内聚,低耦合”。
    • 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
    • 低耦合 :仅对外暴露少量的方法用于使用。
  • 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。

使用者对类内部定义的属性(对象的成员变量)的直接操作会导致数据的错误、混乱或安全性问题。

class Animal {
    public int legs;
    public void eat(){
        System.out.println("Eating");
    }
    public void move(){
        System.out.println("Moving.");
    }
}
public class Zoo {
    public static void main(String args[]) {
        Animal xb = new Animal();
        xb.legs = 4;
        System.out.println(xb.legs);
        xb.eat();
        xb.move();
    }
}

1、信息的封装和隐藏
Java中通过将数据声明为私有的(private),再提供公共的(public)方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:

  • 隐藏一个类中不需要对外提供的实现细节;
  • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
  • 便于修改,增强代码的可维护性;
/**
 * 一、面型对象的特性一:封装与隐藏
 *  当我们创建一个对象的类以后,我们可以通过 “对象.属性” 的方式,对对象的属性进行赋值。
 *  这里,赋值的操作要受到属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。
 *  但是,在实际问题当中,我们往往需要给属性赋值加入额外的限制条件,这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。
 *  比如 setLegs(),同时我们需要避免用户再使用 “对象.属性” 的方式进行赋值。则需要将属性声明为私有的(private)
 *  此时针对于属性就体现了封装性
 *
 * 二、封装性的体现
 *  我们将类的属性私有化(private),同时,提供公共的方法来获取(getXxx)和设置(setXxx)
 *
 *      拓展:封装性的体现有很多
 *          (1) 如上
 *          (2)不对外暴露的私有的方法
 *          (3)单例模式 ...
 *
 * 三、封装性的体现,需要权限修饰符来配合
 *  1、Java规定的4种权限:private、缺省、protected、public
 *  2、4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
 *     修饰类的话只能用public、缺省
 *
 *  总结封装性:Java提供了4种权限修饰符来修饰类以及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。
 */
public class AnimalTest {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.name = "大黄";
//        animal.age = 2; //'age' has private access
        animal.setAge(2);
//        animal.legs = 4; //'legs' has private access
        animal.setLegs(4);
        animal.show();
 
//        animal.legs = -4;
        animal.setLegs(-4);
        animal.show();
 
        int legs = animal.getLegs();
        System.out.println(legs);
    }
}
 
class Animal{
    String name;
    private int age;
//    int legs; //腿的个数
    private int legs; //腿的个数
 
    //对属性的设置
    public void setLegs(int l){
        if (l >= 0 && l % 2 == 0){
           legs = l;
        }else {
            legs = 0;
        }
    }
 
    //对属性的获取
    public int getLegs(){
        return legs;
    }
 
    //提供age的get和set方法
    public int getAge(){
        return age;
    }
 
    public void setAge(int a){
        if (age >= 0){
            age = a;
        }else {
            age = 0;
        }
    }
 
    public void eat(){
        System.out.println("动物进食");
    }
 
    public void show(){
        System.out.println("[ name = "  + name + ", age = " + age + ", legs = " + legs + " ]" );
    }
}
 

2、四种访问权限修饰符
Java权限修饰符public、protected、(缺省)、private置于类的成员定义前,用来限定对象对该类成员的访问权限。
image
对于class的权限修饰只可以用public和default(缺省)。

  • public类可以在任意地方被访问。
  • default类只可以被同一个包内部的类访问。
    3.练习
    。。。
    八、类的成员之三:构造器
/**
 * 类的结构之三:构造器(或构造方法、constructor)的使用
 * construct:建设、构造 construction:CCB constructor:建设者
 *
 * 一、构造器的作用
 * 1、创建对象
 * 2、初始化对象的信息
 *
 * 二、说明
 * 1、如果没有显示的定义构造器的话,则系统默认提供一个空参的构造器
 * 2、定义构造器的格式:权限修饰符 类名(形参列表){}
 * 3、一个类中定义的多个构造器,彼此重载
 * 4、一旦我们显示的定义了类的构造器之后,系统就不再提供空参的构造器
 * 5、一个类中,至少有一个构造器
 *
 */
 /**
 * @author: huxingxin
 * @date: 2022/12/2 15:27:19
 * @description:
 *
 * 类的结构之三:构造器(或构造方法、constructor)的使用
 * construct:建设、构造 construction:CCB constructor:建设者
 *
 * 一、构造器的作用
 * 1、创建对象
 * 2、初始化对象的信息
 *
 * 二、说明
 * 1、如果没有显示的定义构造器的话,则系统默认提供一个空参的构造器
 * 2、定义构造器的格式:权限修饰符 类名(形参列表){}
 * 3、一个类中定义的多个构造器,彼此重载
 * 4、一旦我们显示的定义了类的构造器之后,系统就不再提供空参的构造器
 * 5、一个类中,至少有一个构造器
 *
 */
public class PersonTest {
    public static void main(String[] args) {
        //创建类的对象:new + 构造器
        Person person1 = new Person();
        person1.eat();
 
        Person person2 = new Person("张三");
        String name = person2.name;
        System.out.println(name);
 
    }
}
 
class Person{
    //属性
    String name;
    int age;
 
    //构造器
    public Person(){
        System.out.println("Person的构造器...");
    }
 
    public Person(String n){
        name = n;
    }
 
    public Person(String n, int a){
        name = n;
        age = a;
    }
 
    //方法
    public void eat(){
        System.out.println("人吃饭...");
    }
 
    public void study(){
        System.out.println("人学习...");
    }
}
 

1、构造器的特征

它具有与类相同的名称

它不声明返回值类型。(与声明为void不同)

不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值

2、构造器的作用

创建对象;给对象进行初始化

如:Order o = new Order(); Person p = new Person(“Peter”,15);

如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的构造器中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自

动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们要“洗澡”了。

3、语法格式

修饰符 类名 (参数列表) {
    初始化语句;
}

4、举例:

public class Animal {
    private int legs;
    //构造器
    public Animal() {
        legs = 4;
    }
    public void setLegs(int i){
        legs = i;
    }
    public int getLegs(){
        return legs;
    }

    public static void main(String[] args) {
        Animal a = new Animal();
        System.out.println(a.getLegs());
    }
}

5、构造器分类

  • 根据参数不同,构造器可以分为如下两类:
    • 隐式无参构造器(系统默认提供)
    • 显式定义一个或多个构造器(无参、有参)
  • 注 意:
    • Java语言中,每个类都至少有一个构造器
    • 默认构造器的修饰符与所属类的修饰符一致
    • 一旦显式定义了构造器,则系统不再提供默认构造器
    • 一个类可以创建多个重载的构造器
    • 父类的构造器不可被子类继承

6、构造器重载
构造器一般用来创建对象的同时初始化对象。如

class Person{
    String name;
    int age;
    public Person(String n , int a){ name=n; age=a;}
}

构造器重载使得对象的创建更加灵活,方便创建各种不同的对象。

public class Person{
    public Person(String name, int age, Date d) {this(name,age);…}
    public Person(String name, int age) {…}
    public Person(String name, Date d) {…}
    public Person(){…}
}

构造器重载,参数列表必须不同
构造器重载举例

public class Person { 
    //构造器重载举例
    private String name;
    private int age;
    private Date birthDate;
    public Person(String n, int a, Date d) {
        name = n;
        age = a;
        birthDate = d;
    }
    public Person(String n, int a) {
        name = n;
        age = a;
    }
    public Person(String n, Date d) {
        name = n;
        birthDate = d;
    }
    public Person(String n) {
        name = n;
        age = 30;
    }
}

7、属性赋值过程

/**
 * 总结:属性赋值的先后顺序
 * (1)默认初始化
 * (2)显示初始化
 * (3)构造器初始化
 * (4)通过 “对象.方法” 或者 “对象.属性”方式进行赋值
 *
 * 以上操作的先后顺序 (1) (2) (3) (4)
 */
public class UserTest {
    public static void main(String[] args) {
        User user = new User();
        int age1 = user.getAge();
        System.out.println("age: " + age1);
 
        user.setAge(100);
        int age2 = user.getAge();
        System.out.println("age: " + age2);
    }
}
 
class User{
    String name;
    int age = 1;
 
    public User(){
        age = 2;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int a) {
        age = a;
    }
}
 

截止到目前,我们讲到了很多位置都可以对类的属性赋值。现总结这几个位置,并指明赋值的先后顺序。

  • 赋值的位置:
    • ① 默认初始化
    • ② 显式初始化
    • ③ 构造器中初始化
    • ④ 通过“对象.属性“或“对象.方法”的方式赋值
  • 赋值的先后顺序:
  • ① - ② - ③ - ④

8.JavaBean

  • JavaBean是一种Java语言写成的可重用组件。
  • 所谓javaBean,是指符合如下标准的Java类:
    • 类是公共的
    • 有一个无参的公共的构造器
    • 有属性,且有对应的get、set方法
  • 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP
  • 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
/**
 * JavaBean是一种Java语言写的可重用的组件
 * 所谓JavaBean,是指符合以下标准的Java类
 * (1)类是公共的
 * (2)有一个无参的公共的构造器
 * (3)有属性,且有对应的get、set方法
 */
public class Custom {
    private int id;
    private String name;
 
    public int getId() {
        return id;
    }
 
    public Custom() {
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}
 

9、UML类图
image

  1. +表示 public 类型, - 表示 private 类型,#表示protected类型
  2. 方法的写法: 方法的类型(+、-) 方法名(参数名: 参数类型):返回值类型

10.练习

九、关键字:this

/**
 * this关键字的使用
 * 1、this可以用来修饰、调用:属性、方法、构造器
 * 2、this修饰属性和方法
 *  this理解为当前对象 或 当前正在创建的对象
 *
 *      2.1 在类的方法中,我们可以使用 “this.属性” 或 “this.方法” 的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略 “this.”。
 *  特殊情况下,如果方法的形参和类的属性重名时,我们必须显示的使用 “this.属性”,表明此变量是属性,而非形参。
 *
 *      2.2 在类的构造器中,我们可以使用 “this.属性” 或 “this.方法” 的方式,调用当前正在创建的对象属性或方法。但是,通常情况下,我们都选择省略 “this.”。
 *  特殊情况下,如果方法的形参和类的属性重名时,我们必须显示的使用 “this.属性”,表明此变量是属性,而非形参。
 *
 * 3、this调用构造器
 *      3.1 我们在类的构造器中,可以显示的使用 “this(形参列表)” 方式,调用本类中指定的其它构造器。
 *      3.2 构造器中不能通过 “this(形参列表)” 方式调用自己
 *      3.3 如果一个类中有n个构造器,则最多有 n-1 个构造器中使用了 “this(形参列表)”
 *      3.4 规定:“this(形参列表)” 必须声明在当前构造器的首行。
 *      3.5 构造器内部,最多只能声明一个 “this(形参列表)” 方式,用来调用其他构造器。
 */
 public class PersonTest {
    public static void main(String[] args) {
 
    }
}
 
class Person{
    private String name;
    private int age;
 
    public Person() {
    }
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}

1、this是什么?
在Java中,this关键字比较难理解,它的作用和其词义很接近。

  • 它在方法内部使用,即这个方法所属对象的引用;

    • 它在构造器内部使用,表示该构造器正在初始化的对象。
    • this 可以调用类的属性、方法和构造器
  • 什么时候使用this关键字呢?

  • 当在方法内需要用到调用该方法的对象时,就用this。

  • 具体的:我们可以用this来区分属性和局部变量。

  • 比如:this.name = name;

2、使用this,调用属性、方法

  • 在任意方法或构造器内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性。不过,通常我们都习惯省略this。

  • 当形参与成员变量同名时,如果在方法内或构造器内需要使用成员变量,必须添加this来表明该变量是类的成员变量

  • 使用this访问属性和方法时,如果在本类中未找到,会从父类中查找

class Person{ 
    // 定义Person类
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ; 
        this.age = age ; 
    }
    public void getInfo(){
        System.out.println("姓名:" + name) ;
        this.speak();
    }
    public void speak(){
        System.out.println(“年龄:” + this.age);
    }
}

当前正在操作本方法的对象称为当前对象。

class Person{ 
    // 定义Person类
    String name;
    Person(String name){
        this.name = name;
    }
    public void getInfo(){
        System.out.println("Person类 --> " + this.name) ; 
    }
    public boolean compare(Person p){
        return this.name==p.name;
    } 
}
public class PersonTest{
    public static void main(String args[]){
        Person per1 = new Person("张三") ;
        Person per2 = new Person("李四") ;
        per1.getInfo() ; // 当前调用getInfo()方法的对象是per1
        per2.getInfo() ; // 当前调用getInfo()方法的对象是per2
        boolean b = per1.compare(per2);
    } 
}

3、使用this调用本类的构造器

class Person{ 
    // 定义Person类
    private String name ;
    private int age ;
    public Person(){ // 无参构造器
        System.out.println("新对象实例化") ;
    }
    public Person(String name){
        this(); // 调用本类中的无参构造器
        this.name = name ;
    }
    public Person(String name,int age){
        this(name) ; // 调用有一个参数的构造器
        this.age = age;
    }
    public String getInfo(){
        return "姓名:" + name + ",年龄:" + age ;
    } 
}

4、注意:

  • 可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其他的构造器!
  • 明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器
  • 如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了"this(形参列表)"
  • "this(形参列表)"必须声明在类的构造器的首行!
  • 在类的一个构造器中,最多只能声明一个"this(形参列表)"

十、关键字package、import

posted @ 2025-01-05 14:04  吃俺老孙一棒槌  阅读(30)  评论(0)    收藏  举报