八 【java基础】面向对象(上)

这篇博客详细介绍了Java的面向对象特性,包括类、对象的创建与使用,类的成员如属性和方法,以及构造器、封装、this关键字的使用。内容涵盖面向对象的基本概念、方法的重载、可变参数、参数传递机制和递归方法的调用。此外,还讲解了封装和隐藏的概念以及构造器的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

01 面向过程与面向对象

02 类与对象

2.1 Java 类及类的成员

2.2 对象的创建与使用

2.3 对象的创建和使用:内存解析

03 类的成员之一:属性(filed)

 04 类的成员之二:方法

4.2 对象数组的内存解析

 4.3 匿名对象的使用

 4.5 自定义数组的工具类

 4.6 方法的重载

4.7 可变参数的形参

4.8 方法参数的值传递机制

4.8.1 基本数据类型的参数传递

4.8.2 引用数据类型的值传递

4.8.3 练习2 

4.8.3 练习三

4.8.4 练习四

4.8.5 练习五:将对象作为参数传递给方法

4.9 递归方法的调用

4.9.2 练习一  求f(10)

05 封装与隐藏(针对类的属性)

5.1 四种权限修饰符的理解与测试

 06 构造器(构造类的方法)

6.1 构造器的理解

6.2 构造器练习

 6.3 属性赋值的过程

07 关键词:this的使用

7.2 练习一

 8 关键词: package 、import的使用

8.1 package介绍

8.2 MVC设计模式

 8.3 import介绍


01 面向过程与面向对象

面向过程(Procedure Oriented Programming)

面向对象是相对于面向过程而言的。面向过程, 强调的是 功能 行为,以函数为最小单位,考虑怎么做

面向对象(Object Oriented Programming)

面向对象,将功能封装进对象, 强调具备了功能 的 对象,以类 对象为最小单位,考虑谁来做。

 面向对象内容的三条主线

  • Java 类及类的成员:
    • 属性、方法、构造器、代码块、内部类 *
  • 面向对象的三大特征:
    • 封装、继承、多态性、(抽象性) *
  • 其它关键字:
    • this、super、static、final、abstract、interface、package、import 等 
       

面向对象思想概述

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

02 类与对象

面向对象的两个要素

  •  :对一类事物的描述,是抽象的、概念上的定义
  •  对象:是实际存在的该类事物的每个个体,因而也称为实    例(instance)。

 可以理解为:类= 抽象概念的人;对象= 实实在在的某个人
 面向对象程序设计的重点是类的设计
 设计类,其实就是设计类的成员

2.1 Java 类及类的成员

Java 中常见的类的成员有:

  • 属性:对应类中的成员变量
  • 行为:对应类中的成员方法

举例一

举例二 

2.2 对象的创建与使用

类的语法格式

public class Person{
    private int age;    // 声明私有变量age

    public void showAge(int i){ //声明方法 showAge
        age = i;
    }
}

 创建一个自定义类

public class PersonTest {
    public static void main(String[] args) {
        // 2. 在主程序中新建一个类的实例
       //  类名对象名= new 类名();
        Person Zhangsan = new Person();

        // 调用类的结构:属性和方法
        Zhangsan.name = "Zhangsan";
        Zhangsan.age = 17;
        Zhangsan.isMale = true;
        System.out.println(Zhangsan.name); // Zhangsan
        System.out.println(Zhangsan.age); // 17

        // 调用方法
        Zhangsan.eat();
        Zhangsan.sleep();
        Zhangsan.talk();

        //****************
        Person P2 = new Person();
        //不定义初始值
        System.out.println(P2.name); //null
        System.out.println(P2.isMale); // false

        //**************
        Person p3 = Zhangsan;  //将 p1 变量保存的对象地址值赋给 p3,导致 p1 和 p3 指向了堆空间中的一个对象实体。
        System.out.println(p3.name); // Zahngsan

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

    }
}

    /*
   1. 声明一个类
    修饰符 class 类名{
  		属性声明;
  		方法声明;
  }
  说明:修饰符 public:类可以被任意访问类的正文要用{  }括起来
     */
    class Person{
        // 类的属性
        String name;
        int age;
        boolean isMale;

        // 定义方法
        public void eat(){
            System.out.println("eating");
        }

        public void sleep(){
            System.out.println("Sleeping");
        }

        public void talk(){
            System.out.println("talking");
        }
    }

 文字说明

  •  创建对象语法: 类名 对象名 = new 类名
  • 使用“ 对象名.对象成员 ”的方式访问对象成员(包括属性和 方法)
  • 如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰。(Zhangsan 和Lisi 是两个人)

类的访问机制:

  • 在一个类中的访问机制: 类中的方法可以直接访问类中的成员变量 。
    • 例外: static 方法访问非 static 编译不通过 。(static方法和类同时加载,非静态方法需要创建一个对象后才加载)
  • 在不同类中的访问机制: 先创建要访问类的对象 再用对象访问类中定义的成员 。

2.3 对象的创建和使用:内存解析

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

 举例

p1 = new Person
p1.name = "Tom";
p1.isMale = true

Person p2 = new Person
sysout(p2.name);//null

Person p3 = p1
p3.age = 10;

03 类的成员之一:属性(filed)

语法格式

变量分类

  •  在方法体外,类体内声明的变量称为成员变量(属性)
  • 方法体内部声明的变量称为局部变量。

 属性和局部变量的异同点

  •  相同点:
    • 定义变量的格式:数据类型 变量名 = 变量值
    • 先声明,后使用
    •  变量都有其对应的作用域
  • 不同点:
    • 在类中声明的位置不同
      •  属性:直接定义在类的一对{}内
      • 局部变量:声明在方法内、方法形参、构造器形参、构造器内部的变量
    •  关于权限修饰符的不同
      • 属性:可以在声明属性时,指明其权限,使用权限修饰符。
        • 常用的权限修饰符:private、public、缺省、protected
        • 目前声明属性时,都使用缺省即可。
      • 局部变量:不可以使用权限修饰符。
    • 默认初始化值的情况:
      •  属性:类的属性,根据其类型,都有默认初始化值。
        • 整型(byte、short、int、long):0
        • 浮点型(float、double):0.0
        • 字符型(char):0(或‘\u0000’)
        • 布尔型(boolean):false
        •  引用数据类型(类、数组、接口):null
    • 局部变量:没有默认初始化值
      •  意味着:在调用局部变量之前,一定要显式赋值
      • 特别地:形参在调用时,赋值即可。
    •  在内存中加载的位置,亦各不相同。
      • 属性:加载到空间中(非 static)
      • 局部变量:加载到空间

举例

public class UserTest {
    public static void main(String[] args){
        // 创建实例调用user
        User u1 = new User();
        System.out.println(u1.name);// null
        System.out.println(u1.age); //0

        u1.talk("English"); //实参
    }
}

class User{
    // 属性或成员变量
    String name; //不加Private 或public即为缺省
    public int age;
    boolean isMale;

    // 方法
    public void talk(String language){  // 形参 也是局部变量
        System.out.println("Talking " + language);
    }

    public void eat(){
        String food = "饼";  // 局部变量
        System.out.println("he likes" + food);
    }

}

 练习

/*
创建学生类,并调用方法返回其信息
*/

public class StudentTest {
    public static void main(String[] args){
        Student s1 = new Student();
        s1.name = "zhangsan";
        s1.age = 24;

        s1.say();
    }
}

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

    public void say(){
        System.out.println("This Student'name is " + name + " " + age + " years old");
    }
}

 04 类的成员之二:方法

方法定义

 什么是方法(method 、函数)

  • 方法 是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
  • 将功能封装为方法的目的: 可以实现代码重用,简化代码
  • Java 里的方法不能独立存在,所有的方法必须定义在类 里。

 举例

public class Person{
    private int age;

    public int getAge(){ // 声明方法 getAge()
        return age;
    }

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

文字说明 

/*
 * 类中方法的声明和使用
 * 
 * 方法:描述类应该具有的功能。
 * 比如:Math类:sqrt()\random() \...
 *     Scanner类:nextXxx() ...
 *     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. 说明:
 * 		3.1 关于权限修饰符:默认方法的权限修饰符先都使用public
 * 			Java规定的4种权限修饰符:private、public、缺省、protected  -->封装性再细说
 * 
 * 		3.2 返回值类型: 有返回值  vs 没有返回值
 * 			3.2.1  如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用
 *                return关键字来返回指定类型的变量或常量:“return 数据”。
 * 				  如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要
 *               使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。
 * 
 * 			3.2.2 我们定义方法该不该有返回值?
 * 				① 题目要求
 * 				② 凭经验:具体问题具体分析
 * 
 *      3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”

 *      3.4 形参列表:方法名可以声明0个、1个,或多个形参。
 *      	3.4.1 格式:数据类型1 形参1,数据类型2 形参2,...
 *      
 *      	3.4.2 我们定义方法时,该不该定义形参?
 *      		① 题目要求
 *      		② 凭经验,具体问题具体分析

 *      3.5 方法体:方法功能的体现。

 *  4. return关键字的使用:
 *  	1.使用范围:使用在方法体中
 *  	2.作业:① 结束方法
 *  		  ② 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。
 *  	3.注意点:return关键字后不可声明执行语句。

 *  5. 方法的使用中,可以调用当前类的属性或方法。
 *  		特殊的:方法A中又调用了方法A:递归方法。
 *  	方法中不能定义其他方法。
 */

 代码举例一

public class PersonTest {
	public static void main(String[] args) {
		Person p1 = new Person();
		
		p1.name = "Jerry";
		p1.age = 17;
		p1.sex = 1;
		
		p1.study();
		
		p1.showAge();
		
		int newAge = p1.addAge(2);
		System.out.println(p1.name + "的年龄为" + newAge);
		
		System.out.println(p1.age);	//19
		
		//*******************************
		Person p2 = new Person();
		p2.showAge();	//0
		p2.addAge(10);
		p2.showAge();	//10
		
		p1.showAge();	//20
	}
}

class Person{
        // 类的属性
        String name;
        int age;
        int sex;

        // 定义方法
        public void study(){
            System.out.println("Studying");
        }

        public void showAge(){
            System.out.println("今年 " + age + " 岁");
        }

        public int addAge(int i){
            age += 1;
            return age;
        }
    }

 练习二(方法)

public class MethodTesr {
    public static void main(String[] args) {
        // 方法必须写在类中,且在调用之前要新建一实例
        MethodTesr test = new MethodTesr();
        test.Print();
    }
    public void Print(){
        for (int i = 0; i< 8; i++){
            for(int j = 0; j< 10; j++){
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

public class MethodTesr {
    public static void main(String[] args) {
        // 方法必须写在类中,且在调用之前要新建一实例
        MethodTesr test = new MethodTesr();
        int area = test.Printarea();
        System.out.println(area);
    }
    public int Printarea(){
        for (int i = 0; i< 8; i++){
            for(int j = 0; j< 10; j++){
                System.out.print("*");
            }
            System.out.println();
        }
        return 10 * 8;
    }
}

练习三(对象数组)

/*
定义类 Student ,包含三个属性:学号 number(int) ,年级 state(int) ,成绩
score(int) 。 创建 20 个学生对象,学号为 1 到 20 ,年级和成绩都由随机数 确定。
问题一:打印出 3 年级 (state 值为 3 )的学生信息 。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
 */
public class StudentTest {
    public static void main(String[] args){
        Student[] student = new Student[20]; //声明一个Student类型的数组

        for(int i = 0; i< student.length ; i++) {
            student[i] = new Student(); // 创建实例
            student[i].number = i + 1; // 学号
            student[i].score = (int) (Math.random() * (100 + 1)); // 0-100
            student[i].state = (int) (Math.random() * 6 + 1);// 1-6

            // 打印年级为3 的学生信息
            if (student[i].state == 3) {
                String info = student[i].info();
                System.out.println(info);
            }
        }
        System.out.println();
            // 冒泡排序成绩
        for (int i = 0; i < student.length; i++){
            for(int j = 0 ; j < student.length - 1 - i; j++){
                if (student[j].score < student[j+1].score){ //冒泡排序是内层排序
                    // 这里要交换student对象,不是数值
                    Student temp = student[j];  // 新建一个Student对象用于储存交换值
                    student[j] = student[j+1];
                    student[j+1] = temp;
                }
            }
        }

            // 遍历学生信息
        for (int i = 0; i < student.length; i++){
            System.out.println(student[i].info());
        }
        }

}

// 创建学生类
class Student{
    int number;
    int state;
    int score;

    public String info(){
        return "学号 " + number + " 年级 " + state + " 成绩 " + score;
    }

}

练习三的优化(重构方法)

public class StudentTest2 {
    public static void main(String[] args) {
        Student2[] student = new Student2[20]; //声明一个Student类型的数组

        for (int i = 0; i < student.length; i++) {
            student[i] = new Student2(); // 创建实例
            student[i].number = i + 1; // 学号
            student[i].score = (int) (Math.random() * (100 + 1)); // 0-100
            student[i].state = (int) (Math.random() * 6 + 1);// 1-6
            //
        }

        StudentTest2 test = new StudentTest2();  // 调用类中的方法前要实例化这个类

        test.search(student, 3); // 实参也是数组和int型的数值
        System.out.println();  

        test.bubbleSort(student); // 实参也为一个数组
        test.print(student);
    }

    // 构造方法
    // 遍历数组
    public void print(Student2[] student) {  // 形参为一个数组
        for (int i = 0; i < student.length; i++) {
            System.out.println(student[i].info());
        }
    }

    // 打印为3
    public void search(Student2[] student, int state) { // 形参为数组和int 型的数值
        for (int i = 0; i < student.length; i++) {
            if (student[i].state == state) {
                String info = student[i].info();
                System.out.println(info);
            }
        }
    }

    // 排序

    public void bubbleSort(Student2[] student) {
        for (int i = 0; i < student.length; i++) {
            for (int j = 0; j < student.length - 1 - i; j++) {
                if (student[j].score < student[j + 1].score) {
                    // 交换student对象
                    Student2 temp = student[j];
                    student[j] = student[j + 1];
                    student[j + 1] = temp;
                }
            }
        }

        //
    }
}

class Student2 {
    int number;
    int state;
    int score;

    public String info() {
        return "学号 " + number + " 年级 " + state + " 成绩 " + score;
    }
}

4.2 对象数组的内存解析

/*引用类型的变量,只可能存储量两类值:null或地址值(含变量类型)*/
Student[] stus= newStudent[5]; //Student类型的数组
stus[0] = new Student();

sysout(stus[0].state);//1
sysout(stus[1]);//null

sysout(stus[1].number);//异常

stus[1] = new Student();

sysout(stus[1].number);//0

class Student{
  int number;//学号
  int state = 1;//年级
  int score;//成绩
}

堆:存放new出来的东西

 4.3 匿名对象的使用

  • 理解:我们创建的对象,没有显示的赋值给一个变量名。即为匿名对象。
  • 特征:匿名对象只能调用一次。

使用


public class InstanceTest {
	public static void main(String[] args) {
// 实例对象
		Phone p = new Phone();
//		p = null;
		System.out.println(p);
		
		p.sendEmail();
		p.playGame();
		
		//匿名对象 不给实例出来的对象命名
//		new Phone().sendEmail();
//		new Phone().playGame();
		
		new Phone().price = 1999;
		new Phone().showPrice();	//0.0
		
		//*******************************
		PhoneMall mall = new PhoneMall();
//		mall.show(p);
		//匿名对象的使用
		mall.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);
	}
}

 4.5 自定义数组的工具类

public class ArrayUtil {
    /*
     * 自定义数组工具类
     */

        // 求数组的最大值
        public int getMax(int[] arr) {
            int maxValue = arr[0];
            for (int i = 1; i < arr.length; i++) {
                if (maxValue < arr[i]) {
                    maxValue = arr[i];
                }
            }
            return maxValue;
        }

        // 求数组的最小值
        public int getMin(int[] arr) {
            int minValue = arr[0];
            for (int i = 1; i < arr.length; i++) {
                if (minValue > arr[i]) {
                    minValue = arr[i];
                }
            }
            return minValue;
        }

        // 求数组总和
        public int getSum(int[] arr) {
            int sum = 0;
            for (int i = 0; i < arr.length; i++) {
                sum += arr[i];
            }
            return sum;
        }

        // 求数组平均值
        public int getAvg(int[] arr) {
            int avgValue = getSum(arr) / arr.length;
            return avgValue;
        }

        // 反转数组
        public void reverse(int[] arr) {
            for (int i = 0; i < arr.length / 2; i++) {
                int temp = arr[i];
                arr[i] = arr[arr.length - i - 1];
                arr[arr.length - i - 1] = temp;
            }
        }

        // 复制数组
        public int[] copy(int[] arr) {
            int[] arr1 = new int[arr.length]; //复制数组
            for (int i = 0; i < arr1.length; i++) {
                arr1[i] = arr[i];
            }
            return null;
        }

        // 数组冒泡排序
        public void sort(int[] arr) {
            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;
                    }
                }
            }
        }

        // 遍历数组
        public void print(int[] arr) {
            System.out.print("[");
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i] + ",");
            }
            System.out.println("]");
        }

        // 查找指定元素
        public int getIndex(int[] arr, int dest) {
            //线性查找
            for (int i = 0; i < arr.length; i++) {
                if (dest==arr[i]) {
                    return i;
                }
            }
            return -1; // 没找到的化反回-1
        }
    }

对工具组测试


public class ArrayUtilTest {


	public static void main(String[] args) {
		ArrayUtil util = new ArrayUtil();
		int[] arr = new int[]{32,5,26,74,0,96,14,-98,25};
		int max = util.getMax(arr);
		System.out.println("最大值为:" + max);
		
//		System.out.print("排序前:");
//		util.print(arr);
//		
//		util.sort(arr);
//		System.out.print("排序后:");
//		util.print(arr);
		
		System.out.println("查找:");
		int index = util.getIndex(arr, 5);
		if(index > 0){
			System.out.println("找到了,索引地址:" + index);
		}else{
			System.out.println("没找到");
		}
	}
}

 4.6 方法的重载

重载的概念

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

重载特点

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

示例

  • //返回两个整数的和
    • 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 OverloadTest {
   public static void main(String[] args){
       OverloadTest test = new OverloadTest();
       test.getSum(1,2);//3
       test.getSum(1.0,2.0);//double
   }

   // 以下方法重载getSum()
    public void getSum(int i, int j){
        System.out.println(3);
    }

    public void getSum(float i, float j){
        System.out.println(3.0);
    }

    public void getSum(double i, double j){
        System.out.println("double");
    }

}

4.7 可变参数的形参

JavaSE 5.0 中提供了Varargs(variable number of arguments)机制,允许直接定义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。

说明

  •  声明格式: 方法名 (参数的类型名…参数名)
  • 可变 参数:方法参数部分指定类型的参数个数是可变 多 个: 0 个, 1 个或多个
  • 可变 个数形参的方法与同名的方法之间,彼此构成重载
  • 可变 参数方法的使用与方法参数部分使用数组是一致的
  • 方法 的参数部分有可变形参,需要放在形参声明 的 最后
  • 在一个方法的形参位置,最多只能声明一个可变个数形参

举例 

public class MethodArgs {
    public static void main(String[] args) {
        MethodArgs arrgs = new MethodArgs();
        arrgs.show(12);
        arrgs.show(new String[] {"AA", "BB","CC"});

    }

// 下面的三个方法彼此构成重构
    public void show(int i){

    }

    public void show(String... strs){ // 可变参数使用方法参数部分与数组一致
        System.out.println("show(String ...strs)");
        for(int j = 0; j < strs.length ; j++){
            System.out.println(strs[j]);
        }
    }

    public void show(int i, String...strs){

    }
}

4.8 方法参数的值传递机制

关于变量的赋值

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

  • 如果变量是基本数据类型,此时赋值的是变量所保存的数据值
  • 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值
    public static void main(String[] args) {
        // 基本数据类型
        int m = 10;
        int n = m;

        System.out.println("m = " + m + "," + "n = " + n); // m= 10,n=10

        n = 20;

        System.out.println("m = " + m + "," + "n = " + n);// m=10.n=20

        // 引用数据类型
        Order o1 = new Order();
        o1.oderId = 1001;

        Order o2 = o1;	//赋值后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体
        System.out.println("o1.orderId = " + o1.oderId + ",o2.orderId = " + o2.oderId); 
        // o1.orderId = 1001,o2.orderId = 1001

        o2.oderId = 1002;
        System.out.println("o1.orderId = " + o1.oderId + ",o2.orderId = " + o2.oderId);
        // o1.orderId = 1002,o2.orderId = 1002
    }
}

class Order{
     int oderId;
}

4.8.1 基本数据类型的参数传递

public class ValueTransferTest1 {
    public static void main(String[] args) {
        int m = 10;
        int n = 20;
        System.out.println("m = " + m + " n= " + n); // 10, 20

        ValueTransferTest1 test = new ValueTransferTest1();
        
        test.swap(m, n);
        // 交换后数值
        System.out.println("m = " + m + " n= " + n); 
        // 10, 20 这里只交换了swap内的参数,main中的mn 不受影响
    }

    public void swap(int m,int n){
        int temp = m;
        m = n;
        n =temp;
    }
}

4.8.2 引用数据类型的值传递

如果参数是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值

public class ValueTest {
    /*
     *  如果参数是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值。
     */

        public static void main(String[] args) {
            Data data = new Data();

            data.m = 10;
            data.n = 20;

            System.out.println("m = " + data.m + ", n = " + data.n); //10 20
            
            ValueTest test = new ValueTest();
            test.swap(data);

            System.out.println("m = " + data.m + ", n = " + data.n);// 20 10

        }

        public void swap(Data data){
            int temp = data.m;
            data.m = data.n;
            data.n = temp;
        }
    }

    class Data{

        int m;
        int n;
    }

练习-> 确定输出结果 

public class TransferTest3{
	public static void main(String args[]){
		TransferTest3 test=new TransferTest3();// 在堆中添加一个新的对象
		test.first();
	}
	
	public void first(){
		int i=5;
		Value v=new Value();
		v.i=25;
		second(v,i);               // 运行完second之后,second中定义的变量就出栈了
		System.out.println(v.i);
	}
	
	public void second(Value v,int i){
		i=0;
		v.i=20;
		Value val=new Value();
		v=val;
		System.out.println(v.i+" "+i);
		
	}
}
class Value {
	int i= 15;
} 


// 15,0,20

4.8.3 练习2 

public static void method(int a,int b){
	a = a * 10;
	b = b * 20;
	System.out.println(a);
	System.out.println(b);
	System.exit(0); // 终止程序
}

4.8.3 练习三

/*
 * 微软:
 * 定义一个int型的数组:int[] arr = new int[]{12,3,3,34,56,77,432};
 * 让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值。遍历新的数组。 
 */
 
//错误写法
for(int i= 0;i < arr.length;i++){
	arr[i] = arr[i] / arr[0];
}

//正确写法1
for(int i = arr.length –1;i >= 0;i--){
	arr[i] = arr[i] / arr[0];
}

//正确写法2
int temp = arr[0];
for(int i= 0;i < arr.length;i++){
	arr[i] = arr[i] / temp;
}

4.8.4 练习四

public class Test {
    public static void main(String[] args) {
        /*
         * int[] arr = new int[10];
         * System.out.println(arr);//地址值?
         *
         * char[] arr1 = new char[10];
         * System.out.println(arr1);//地址值?
         */
                int[] arr = new int[]{1,2,3};
                //传进去的是一个Object的对象
                System.out.println(arr);//地址值

                char[] arr1 = new char[]{'a','b','c'};
                //传进去的是一个数组,直接char型输出为数组
                System.out.println(arr1);//abc
            }
}

这里是因为println的重载,针对char[]类型的输出

    String s1 = "HElloworld1234";
    chs = s1.toCharArray(); // 转换为char型数组
    System.out.println(chs);
    System.out.println("前边加上字符输出的是地址:"+chs);
    System.out.println("Arrays.toString(ch)以数组形式输出:"+Arrays.toString(chs));
                
    /*
    输出:
      HElloworld1234
      前边加上字符输出的是地址:[C@15db9742
      Arrays.toString(ch)以数组形式输出:[H, E, l, l, o, w, o, r, l, d, 1, 2, 3, 4]
    */

4.8.5 练习五:将对象作为参数传递给方法

public class Test6 {
    public static void main(String[] args){
        PassObject object = new PassObject();
        Circle c = new Circle();
        object.printAreas(c, 6);
        System.out.println("new redius  " + c.radius);
    }
}

// ciecle类
class Circle {

    double radius;	//半径

    //返回圆的面积
    public double findArea(){
        return (double)(radius * radius * Math.PI);
    }
}
// passobject类

class PassObject{

    public void printAreas(Circle c, int time){
        System.out.println("Redius" + "\t\t" + "Area");
        for (int i = 1; i <= time; i++){
            c.radius = i;
            System.out.println(i + "\t\t" + c.findArea());
        }
        c.radius = time + 1;

    }
}

4.9 递归方法的调用

  • 递归方法:一个方法体内调用它自身。方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
  • 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
public class RecursionTest {

	public static void main(String[] args) {

		// 例1:计算1-100之间所有自然数的和
		// 方法1:
		int sum = 0;
		for (int i = 1; i <= 100; i++) {
			sum += i;
		}
		System.out.println("sum = " + sum);

		// 方法2:
		RecursionTest test = new RecursionTest();
		int sum1 = test.getSum(100);
		System.out.println("sum1 = " + sum1);
	}

	// 例1:计算1-n之间所有自然数的和
	public int getSum(int n) {

		if (n == 1) {
			return 1;
		} else {
			return n + getSum(n - 1);
		}
	}

	// 例2:计算1-n之间所有自然数的乘积
	//归求阶乘(n!)的算法
	public int getSum1(int n) {


		if (n == 1) {
			return 1;
		} else {
			return n * getSum1(n - 1);
		}
	}
}

4.9.2 练习一  求f(10)

已知 一个数列: f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),其中n 是大于 0 的整数,求 f(10) 的值 。

public class RecursionTest {

	public static void main(String[] args) {

		int value = test.f(10);
		System.out.println(value);
	}

	//例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
	//其中n是大于0的整数,求f(10)的值。
	public int f(int n){
		if(n == 0){
			return 1;
		}else if(n == 1){
			return 4;
		}else{
			return 2*f(n-1) + f(n-2);
		}
	}
	
	//例4:已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),
	//其中n是大于0的整数,求f(10)的值。 
	public int f1(int n){
		if(n == 20){
			return 1;
		}else if(n == 21){
			return 4;
		}else{
			//return 2*f1(n-1) + f1(n-2);// 超出内存限制,递归占用大量内存
               return f1(n + 2) - 2*f1(n + 1);
		}
	}
}

05 封装与隐藏(针对类的属性)

我们程序设计追求“高内聚,低耦合”。

高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用

隐藏对象内部的复杂性,只对外公开简单的接口。

 便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。

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

  • 隐藏 一个类中 不需要对外提供的 实现细节;
  • 使用者只能通过事先定制好的 方法来访问数据 可以方便地加入控制逻辑限制对属性的不合理操作;
  • 便于修改增强代码的可维护性
package OOP_NEW;

public class AnimalTest {
    public static void main(String[] args) {
        Animal a = new Animal();
        a.name = "大黄";
//		a.age = 1;
//		a.legs = 4;//The field Animal.legs is not visible 不能直接调用

        a.eat();

//		a.legs = -4;
//		a.setLegs(6);
        a.setLegs(-6);

//		a.legs = -4;//The field Animal.legs is not visible
        a.eat();

        System.out.println(a.name);
        System.out.println(a.getLegs());
    }
}

class Animal{
    String name;
    private int age;
    private int legs;

    //对于属性的设置 get/set
    public void setLegs(int l){
        if(l >=0 && l%2==0){
            legs = 1;
        }else{
            legs = 0;
        }
    }

    public int  getLegs(){
        return legs;
    }

    public void eat(){
        System.out.println("eating");
    }

    // 对于age的get set方法
    public int getAge(){
        return age;
    }

    public void setAge(int a){
        age = a;
    }

}

5.1 四种权限修饰符的理解与测试

Java 权限修饰符public、protected、default(缺省)、private 置于类的成员定义前,用来限定对象对该类成员的访问权限

对于 class 的权限修饰只可以用 public 和 default(缺省)。

  • public 类可以在任意地方被访问。
  • default 类只可以被同一个包内部的类访问

代码举例 


public class Order {

	private int orderPrivate;
	int orderDefault;
	public int orderPublic;
	
	private void methodPrivate(){
		orderPrivate = 1;
		orderDefault = 2;
		orderPublic = 3;
	}
	
	void methodDefault(){
		orderPrivate = 1;
		orderDefault = 2;
		orderPublic = 3;
	}
	
	public void methodPublic(){
		orderPrivate = 1;
		orderDefault = 2;
		orderPublic = 3;
	}
}

 OrderTest(在相同包内其他类文件调用Order)

public class OrderTest {

	public static void main(String[] args) {
		
		Order order = new Order(); //可以直接设计Order实例
		
		order.orderDefault = 1;
		order.orderPublic = 2;

		//出了 Order 类之后,private的结构就不可调用了
//		order.orderPrivate = 3;//The field Order.orderPrivate is not visible
		
		order.methodDefault();
		order.methodPublic();
		//出了 Order 类之后,私有的结构就不可调用了
//		order.methodPrivate();//The method methodPrivate() from the type Order is not visible
	}
}

在相同项目不同包内调用Order 

import github.Order;

public class OrderTest {

	public static void main(String[] args) {
		Order order = new Order();
		
		order.orderPublic = 2;
		//出了 Order 包之后,private的结构、Default的属性结构就不可调用了
//		order.orderDefault = 1;
//		order.orderPrivate = 3;//The field Order.orderPrivate is not visible
		
		order.methodPublic();
		//出了 Order 类之后,私有的结构、缺省的方法结构就不可调用了
//		order.methodDefault();
//		order.methodPrivate();//The method methodPrivate() from the type Order is not visible
	}
}

 06 构造器(构造类的方法)

6.1 构造器的理解

特征

  • 它具有与类相同的名称
  • 它不声明返回值类型。(与声明为 void 不同)
  • 不能被 static 、 final 、 synchronized 、 abstract 、 native 修饰,不能有return 语句返回 值

作用:创建对象;给对象的属性进行初始化

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

说明

1.如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器。

 2.定义构造器的格式:
 *             权限修饰符  类名(形参列表) { }
 3.一个类中定义的多个构造器,彼此构成重载。
 4.一旦显示的定义了类的构造器之后,系统不再提供默认的空参构造器。
 5.一个类中,至少会有一个构造器 。

public class PersonTest1 {
    public static void main(String[] args) {
        Person1 person = new Person1();  //构造器 用于初始化对象
        person.eat();

        Person1 person1 = new Person1("zhangsan");
        System.out.println(person1.name);
    }
}

class Person1{
    // 属性
    String name;
    int age;

    // 构造器,一个类中可以有多个构造器,彼此构成重载
    public Person1(){
        System.out.println("Person()");
    }

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

    // 方法
    public void eat(){
        System.out.println("人吃饭");
    }

    public void study(){
        System.out.println("人学习");
    }

}

6.2 构造器练习

public class PersonTest1 {
    public static void main(String[] args) {
        Person1 person = new Person1();  //构造器 用于初始化对象
        person.setName("zhangsan");
        System.out.println(person.getName());
        System.out.println(person.getAge());
    }
}

class Person1{

    // 属性
    private String name;
    private int age;

    // 构造器,一个类中可以有多个构造器,彼此构成重载
    public Person1(){
        age = 18; //初始化所有人年龄为18
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 120 || age < 0) {
            age = -1;
        } else {
           age = age;
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        name = name;
    }


    // 方法
    public void eat(){
        System.out.println("人吃饭");
    }

    public void study(){
        System.out.println("人学习");
    }

}

 6.3 属性赋值的过程

/*
 * 总结:属性赋值的先后顺序
 * 
 * ① 默认初始化值
 * ② 显式初始化
 * ③ 构造器中赋值
 * ④ 通过"对象.方法" 或 “对象.属性”的方式,赋值
 * 
 * 以上操作的先后顺序:① - ② - ③ - ④
 * 
 */

public class UserTest {
    public static void main(String[] args) {
		User u = new User();
		
		System.out.println(u.age);
		
		User u1 = new User(2);
		
		u1.setAge(3);
		
		System.out.println(u1.age);
	}
}


class User{
	String name;
	int age = 1;
	
	public User(){
		
	}
	
	public User(int a){
		age = a;
	}
	
	public void setAge(int a){
		age = a;
	}
}

07 关键词:this的使用

this是什么

  •  它在方法内部使用,即这个方法所属对象的引用;
  • 它在构造器内部使用,表示该构造器正在初始化的对象。

 在类的方法中

在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性和方法。 通常情况下,我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名,我们必须显式 的使用"this.变量"的方式,表明此变量是属性,而非形参。 

在类的构造器中

在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用正在创建的对象属性和方法。
但是,通常情况下,我们都选择省略“this.”。特殊情况下,如果构造器的形参和类的属性同名,我们必须显式  的使用"this.变量"的方式,表明此变量是属性,而非形参。

this 调用构造器

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

代码举例

public class PersonTest1 {
    public static void main(String[] args) {
        Person1 p1 = new Person1();

        p1.setAge(1);
        System.out.println(p1.getAge());

        p1.eat();
        System.out.println();

        Person1 p2 = new Person1("jerry", 20);
        System.out.println(p2.getAge());
    }
}

class Person1{

    // 属性
    private String name;
    private int age;

    // this在构造器中使用
    public Person1(){
        this.eat();
        this.age = 18; //初始化所有人年龄为18
        String info = " Person 初始化";
        System.out.println(info);
    }

    public Person1(String name){
        this();
        this.name = name;
    }

    public Person1(int age){
        this();
        this.age = age;
    }

    public Person1(String name, int age){
        this(age);// 必须在构造器首行,构造器另一种方法
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 120 || age < 0) {
            age = -1;
        } else {
            this.age = age;
        }
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }


    // 在方法中使用this
    public void eat(){
        System.out.println("人吃饭");
        this.study();
    }

    public void study(){
        System.out.println("人学习");
    }

}

7.2 练习一

写一个名为 Account 的类模拟账户。该类的属性和方法如下图所示。该类包括的属性:
账号 id ,余额 balance ,年利率 annualInterestRate ;包含的方法:访问器方法 getter 和 setter方法,取款方法 with d raw()raw(),存款方法 deposit() 。

 

public class Account {
    private int id;
    private double balance;
    private double annualInterrestRate;

    // 访问器方法


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public double getAnnualInterrestRate() {
        return annualInterrestRate;
    }

    public void setAnnualInterrestRate(double annualInterrestRate) {
        this.annualInterrestRate = annualInterrestRate;
    }

    // 方法
    public void withdraw(double amount){  // 取钱
        if(amount > this.balance){
            System.out.println("余额不足");
        }else{
            this.balance -= amount;
        }
    }

    public void deposit(double amount){ // 存钱
        if(amount < 0){
            System.out.println("你在逗我");
        }else{
            this.balance += amount;
            System.out.println("成功存入");
        }
        
    }
}

 创建customer类

public class Customer {
    private String firstName;
    private String lastName;
    private Account account; // 声明类的属性

    // 构造器
    public Customer(String f, String l){
        this.firstName = f;
        this.lastName = l;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }
}

 测试(包含main方法的主程序)

/*
写一个测试程序。
 * (1)创建一个 Customer,名字叫 Jane Smith, 他有一个账号为 1000,余额为 2000 元,年利率为 1.23%的账户。
 * (2)对 Jane Smith 操作。存入 100 元,再取出 960 元。再取出 2000 元。
 * 打印出 Jane Smith 的基本信息

 * 成功存入:100.0
 * 成功取出:960.0
 * 余额不足,取款失败
 * Customer  [Smith,  Jane]  has  a  account:  id  is 1000,
 *  annualInterestRate  is 1.23%,  balance  is 1140.0
 */

public class Custmertest {
    public static void main(String[] args) {
        Customer customer = new Customer("Jane", "Smith");
        Account account = new Account();
        account.setId(1000);
        account.setBalance(2000);
        account.setAnnualInterrestRate(0.0123);
        customer.setAccount(account);
        customer.getAccount().deposit(100);  //主要掌握多层调用
        customer.getAccount().withdraw(960);
        customer.getAccount().withdraw(2000);
        System.out.println("Custmor " + customer.getFirstName()  + " " + customer.getLastName() +
                "has an Acount with balance " + customer.getAccount().getBalance() + " the id is "+
                customer.getAccount().getId());
        
    }
}

 8 关键词: package 、import的使用

8.1 package介绍

package 关键字的使用

package 语句作为 Java 源文件的第一条语句,指明该文件中定义的类所在的包。 若缺省该语句,则指定为无名包 。它的格式为:package.顶层包名.子包名

包,属于标识符,遵循标识符的命名规则、规范"见名知意"每“.”一次,就代表一层文件目录。
 

  • 补充:同一个包下,不能命名同名接口或同名类,不同包下,可以命名同名的接口、类。

Java中主要的包

1.java.lang----包含一些 Java 语言的核心类,如 String、Math、Integer、System 和 Thread,提供常用功能
2.java.net----包含执行与网络相关的操作的类和接口。
3.java.io----包含能提供多种输入/输出功能的类。
4.java.util----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
5.java.text----包含了一些 java 格式化相关的类
6.java.sql----包含了 java 进行 JDBC 数据库编程的相关类/接口
7.java.awt----包含了构成抽象窗口工具集(abstractwindowtoolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。B/S  C/S

8.2 MVC设计模式

 

 8.3 import介绍

import:导入

  • 在源文件中显式的使用import结构导入指定包下的类、接口
  • 声明在包的声明和类的声明之间
  • 如果需要导入多个结构,则并列写出即可
  • 可以使用"xxx.*"的方式,表示可以导入xxx包下的所有结构。
  • 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
  • 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类。
  •  7.如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。
  • 8.import static组合的使用:调用指定类或接口下的静态的属性或方法.
import java.util.*;

import account2.Bank;


public class PackageImportTest {

	public static void main(String[] args) {
		String info = Arrays.toString(new int[]{1,2,3});
		
		Bank bank = new Bank();
		
		ArrayList list = new ArrayList();
		HashMap map = new HashMap();
		
		Scanner s = null;	
		
		System.out.println("hello");
		
		UserTest us = new UserTest();
		
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值