Java程序设计基础学习笔记——类与对象、方法、递归、重载、可变参数、作用域、构造器、this

本文介绍了Java中的面向对象编程,包括类作为数据类型、对象的实例化以及属性和行为。讲解了如何创建和使用对象,如养猫问题示例,展示了成员变量、方法的定义和调用,以及方法的参数传递机制。还涉及了对象内存布局、构造器、this关键字、哈希码和对象创建流程等概念。
摘要由CSDN通过智能技术生成

以下笔记整理自B站UP主韩顺平【零基础 快速学Java】韩顺平 零基础30天学会Java课程

OOP

面向对象程序设计(Object Oriented Programming)

类就是数据类型,有属性和行为;对象是一个具体的实例

从类到对象,目前有几种说法:

  1. 创建一个对象

  1. 实例化一个对象

  1. 把类实例化

Java最大的特点就是面向对象

养猫问题(引出类与对象)

public class Object01 {

    public static void main(String[] args) {

        //使用OOP面向对象
        //实例化一只猫【创建一只猫】
        //new Cat() —— 创建一只猫
        //把创建的猫赋给cat1   Cat cat1 = new cat();
        Cat cat1 = new Cat();
        cat1.name = "小白";
        cat1.age = 18;
        cat1.color = "白色";

        //创建了第二只猫,赋给cat2
        Cat cat2 = new Cat();
        cat2.name = "小黄";
        cat2.age = 4;
        cat2.color = "黄色";

        //怎么访问对象的属性
        System.out.println("第1只猫的信息" + cat1.name + " " + cat1.age + 
                            " " + cat1.color);
        System.out.println("第2只猫的信息" + cat2.name + " " + cat2.age + 
                            " " + cat2.color);
    }
}

//使用面向对象的方式来解决养猫问题
//定义一个猫类Cat -> 自定义的数据类型
class Cat {
    //属性
    String name;
    int age;
    String color;

    //后面还可以添加行为
}

对象内存布局

根据数据类型的不同,存放的位置也不同

成员变量 = 属性 = field(字段)

属性是类的一个组成部分,一般是基本数据类型,也可是引用类型(对象,数组)。比如我们前面定义猫类 的 int age 就是属性

属性的定义语法同变量,示例:访问修饰符 属性类型 属性名;

访问修饰符:控制属性的访问范围(public protected private 默认)

properties:属性

创建对象

如果只是声明对象,那它还是空的(null),new之后才开辟空间有地址。

Java 内存的结构分析

1) 栈: 一般存放基本数据类型(局部变量)

2) 堆: 存放对象(Cat cat , 数组等)

3) 方法区:常量池(常量,比如字符串), 类加载信

类与对象练习

编译运行结果如下图:

成员方法

public class Method {

    public static void main(String[] args) {

        //方法使用
        //先创建对象,然后调用方法
        Person p1 = new Person();

        p1.speak(); //调用speak方法
        p1.cal01(); //调用cal01方法
        p1.cal02(50); //调用cal02方法
        
        int returnRes = p1.getSum(10, 20);  //调用getSum方法
        System.out.println("getSum方法返回的值" + returnRes);    
    }
}

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

    //方法(成员方法)
    //添加speak成员方法,输出"我是一个好人"
    //public 表示 方法是公开的
    //void 表示 方法没有返回值
    //speak() speak表示方法名 ()表示形参列表
    //{} 方法体 可以写我们要执行的代码
    public void speak() {

        System.out.println("我是一个好人");
    }

    //添加cal01成员方法,可以计算从1+2+3+...+1000
    public void cal01() {
        int res = 0;
        for( int i = 0; i <= 1000; i ++ ) {
            res += i;
        }
        System.out.println("计算结果=" + res);
    }

    //添加 cal02 成员方法,该方法可以接收一个数 n,计算从 1+..+n 的结果
    //(int n)形参列表,表示当前有一个形参n,可以接收用户的输入
    public void cal02(int n) {
        int res = 0;
        for( int i = 0; i <= n; i ++ ) {
            res += i;
        }
        System.out.println("计算结果=" + res);

    }

    //添加 getSum 成员方法,可以计算两个数的和
    /*
    public 表示 方法是公开的
    int 表示方法执行后返回一个int值
    getSum 方法名
    */
    public int getSum(int num1, int num2) {
        int res = num1 + num2;
        return res;
    }
}

方法的调用机制原理【重点】

成员方法的定义

注意事项

  • 访问修饰符 (作用是控制 方法使用的范围),如果不写默认访问,[有四种: public, protected, 默认, private]

  • 一个方法最多有一个返回值 【如何返回多个结果?返回数组】

  • 如果方法是 void,则方法体中可以没有 return 语句,或者 只写 return ;

  • 方法不能嵌套定义

  • 同一个类中的方法调用,直接调用即可,如下图

  • 跨类中的方法A类调用B类方法,需要通过对象名调用

  • 跨类的方法调用和方法的访问修饰符相关

parameter:参数

基本数据类型的传参机制

基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参【参考方法的调用机制原理图】

引用数据类型的传参机制【重点】

引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参!

看下面代码加深理解【重难点】

public class MethodParameter {

    public static void main(String[] args) {

        B b = new B();
        Person p = new Person();
        p.name = "Jack";
        p.age = 10;

        b.text200(p);

        System.out.println("main中p.age=" + p.age);
        //输出main中p.age=10
    }
}

class Person {

    String name;
    int age;
}

class B {

    public void text200(Person p) {

        //这里并没有影响main栈p对象,只是text200栈中的p置空了
        p = null;
    }
}
public class MethodParameter02 {

    public static void main(String[] args) {

        B b = new B();
        Person p = new Person();
        p.name = "jack";
        p.age = 100;
        b.text300(p);
        System.out.println("main中p.age=" + p.age);
        //输出结果:main中p.age=100
    }
}

class Person {
    String name;
    int age;
}

class B {

    public void text300(Person p) {
        p = new Person(); //会在堆中创建一个新的p对象,text300栈中的p指向这个对象,main栈依然没变
        p.name = "tom";
        p.age = 10;
    }
}

克隆对象

public class MethodExercise02 {

    public static void main(String[] args) {

        Person p = new Person();
        p.name = "milan";
        p.age = 10;

        MyTools tool = new MyTools();
        Person p2 = tool.copyPerson(p);
        System.out.println("p的属性 age = " + p.age + " 名字=" + p.name);
        System.out.println("p2的属性 age = " + p2.age + " 名字=" + p2.name);

    }
}

class Person {
    String name;
    int age;
}

class MyTools {

    public Person copyPerson(Person p) {
        Person p2 = new Person();
        p2.name = p.name;
        p2.age = p.age;
        return p2;
    }
}

递归

recursion:递归

阶乘

factorial:阶乘

public class Recursion {

    public static void main(String[] args) {

        myTool tool = new myTool();
        int res = tool.factorial(10);
        System.out.println("res=" + res);
    }
}

class myTool {

    public int factorial(int n) {
        if(n == 1)
            return 1;
        else
            return factorial(n - 1) * n;
    }
}
/*
10的阶乘3628800
*/

递归重要原则

斐波那契数列

fibonacci:斐波那契

import java.util.Scanner;

public class RecursionExercise01 {

    public static void main(String[] args) {
        
        Scanner myScanenr = new Scanner(System.in);
        System.out.println("请输入一个整数:");
        int n = myScanenr.nextInt();
        myTool tool = new myTool();
        int res = tool.Fibonacci(n);
        System.out.println("第" + n + "项对应的斐波那契数为" + res);

    }
}

class myTool {

    public int Fibonacci(int n) {
        if(n == 1 || n == 2)
            return 1;
        else
            return Fibonacci(n - 1) + Fibonacci(n - 2);
    }
} 
/*
斐波那契数列:1 1 2 3 5 8 13 21 ...
*/

猴子吃桃

第10天要吃的时候只剩1个桃子,问原来第1天有多少桃子?

public class RecursionExercise02 {

    public static void main(String[] args) {

        myTool tool = new myTool();
        int res = tool.Monkey_peach(1);
        System.out.println("res=" + res);  //res=1534
    }
}

class myTool {

    public int Monkey_peach(int n) {
        if(n == 10)
            return 1;
        else
            return (Monkey_peach(n + 1) + 1) * 2;
    }    
}

老鼠出迷宫

import java.util.Scanner;

public class Maze {

    public static void main(String[] args) {

        Scanner myScanner = new Scanner(System.in);
        System.out.println("请输入您要创建的地图大小:");
        int row = myScanner.nextInt();
        int column = myScanner.nextInt();

        //创建一个地图,用二维数组表示
        int[][] map = new int[row][column];
        System.out.println("请绘制地图(每行以空格隔开,0表示没有障碍物,1表示有障碍物):");
        //绘制地图
        for( int i = 0; i < map.length; i ++ ) {
            for(int j = 0; j < map[i].length; j ++ ) {
                map[i][j] = myScanner.nextInt();
            }
        }
        // //设置障碍物,1表示有障碍物,0表示没有障碍物
        // for( int i = 0; i < 7; i ++ ) {
        //     map[0][i] = 1;
        //     map[7][i] = 1;
        // }
        // for( int j = 0; j < 8; j ++ ) {
        //     map[j][0] = 1;
        //     map[j][6] = 1;
        // }
        // map[3][1] = 1;
        // map[3][2] = 1;

        System.out.println("当前地图为:");
        //打印当前地图
        for( int i = 0; i < map.length; i ++ ) {
            for( int j = 0; j < map[i].length; j ++ ) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("===================");
        myTool tool = new myTool();
        tool.findWay(map, 1, 1);

        //打印当前地图
        for( int i = 0; i < map.length; i ++ ) {
            for( int j = 0; j < map[i].length; j ++ ) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }
    }
}

class myTool {

    //对地图的说明:0表示没有障碍物,可以走;1表示有障碍物;2表示可以走;3表示走过,但是死路
    //如果找到出口返回true,反之返回false
    public boolean findWay(int[][] map, int i, int j) {

        if(map[6][5] == 2){  // map[6][5] 为迷宫出口,说明已经找到出口
            return true;
        } else {
            if(map[i][j] == 0) {  //当前位置为0表示可以走
                map[i][j] = 2;  //假设可以走通
                //找路策略:下->右->上->左
                if(findWay(map, i + 1, j)) {  //往下走
                    return true;
                } else if(findWay(map, i, j + 1)) {  //往右走
                    return true;
                } else if(findWay(map, i - 1, j)) {  //往上走
                    return true;
                } else if(findWay(map, i, j - 1)) {  //往左走
                    return true;
                } else {
                    map[i][j] = 3;  //表示走过,但是死路
                    return false;
                }
            } else {
                return false;
            }
        }
    }
}
/*
地图1:
8 * 7
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
地图2:
8 * 7
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 1 1 1 1 0 1
1 1 1 1 0 0 1
1 0 0 0 0 1 1
1 1 1 0 0 0 1
1 1 1 0 0 0 1
1 1 1 1 1 1 1
*/

汉诺塔

public class HanoiTower {

    public static void main(String[] args) {

        myTool tool = new myTool();
        tool.move(3, 'A', 'B', 'C');

    }
}

class myTool {

    //num表示要移动的个数,a,b,c分别表示A塔,B塔,C塔
    public void move(int num, char a, char b, char c) {
        //如果只有一个盘
        if(num == 1) {
            System.out.println(a + "->" + c);
        } else {
            //如果有多个盘,可以看成两个,最下面的和上面的所有盘
            //1.先移动上面所有的盘到b,借助c
            move(num - 1, a, c, b);
            //2.把最下面的盘移动到c
            System.out.println(a + "->" + c);
            //3.再把b塔的所有盘移动到c,借助a塔
            move(num - 1, b, a, c);
        }
    }
}
/*
tool.move(3, 'A', 'B', 'C')
A->C
A->B
C->B
A->C
B->A
B->C
A->C
*/

重载

out是一个对象

注意事项和使用细节

可变参数

Variable parameter:可变参数

java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。就可以通过可变参数实现

public class VarParameter01 {

    public static void main(String[] args) {

        Method m = new Method();
        int res = m.sum(1, 2, 3);
        System.out.println("res=" + res);
    }
}

class Method {

    //可以计算2个数的和,3个数的和,4个数的和,...
    //可以使用方法重载,但较麻烦
    //使用可变参数优化
    /*
    1.int...表示接收的是可变参数,类型是int,即可以接收多个int(0~)
    2.使用可变参数时,可以当做数组来使用,即nums可以当做数组
    3.遍历nums,求和即可
    */
    public int sum(int... nums) {
        System.out.println("接收的参数个数=" + nums.length);
        int res = 0;
        for( int i = 0; i < nums.length; i ++ ) {
            res += nums[i];
        }
        return res;
    }
}

注意事项和使用细节

作用域

scope:作用域

  • 在java编程中,主要的变量就是属性(成员变量)局部变量

  • 我们说的局部变量一般是指在成员方法中定义的变量

  • 全局变量(属性)作用域为整个类体,成员方法可以使用属性

  • 局部变量:除了属性之外的其他变量,作用域为定义它的代码块

  • 全局变量(属性)可以不赋值,直接使用,因为有默认值;局部变量必须赋值后才能使用,因为没有默认值

  • 属性和局部变量可以重名,访问时遵循就近原则

  • 在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名

  • 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁;局部变量生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁,即在一次方法调用过程中生效。

  • 全局变量(属性)可以被本类使用,也可以被其他类使用(通过对象调用);局部变量只能在本类中对应的方法中使用

  • 全局变量(属性)可以加修饰符;局部变量不可以加修饰符

构造器(构造方法)

构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:

1) 方法名和类名相同

2) 没有返回值

3) 在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。

javap指令

练习题

在前面定义的 Person 类中添加两个构造器:

第一个无参构造器:利用构造器设置所有人的 age 属性初始值都为 18

第二个带 pName 和 pAge 两个参数的构造器:使得每次创建 Person 对象的同时初始化对象的 age 属性值和 name 属性值。

分别使用不同的构造器,创建对象.

public class ConstructorExercise {

    public static void main(String[] args) {

        Person p1 = new Person();
        System.out.println("p1.name=" + p1.name + " p1.age=" + p1.age);
        Person p2 = new Person("jack", 20);
        System.out.println("p2.name=" + p2.name + " p2.age=" + p2.age);
    }
}

class Person {

    String name;
    int age;
    //第一个无参构造器:利用构造器设置所有人的 age 属性初始值都为 18
    public Person() {
        age = 18;
    }
    //第二个带 pName 和 pAge 两个参数的构造器:使得每次创建 Person 对象的同时初始化对象的 age 属性值和 name 属性值。
    public Person(String pName, int pAge) {
        name = pName;
        age = pAge;
    }
}
/*
输出结果
p1.name=null p1.age=18
p2.name=jack p2.age=20
*/

面试题——对象创建流程分析【重点】

this

hashCode

返回该对象的哈希码值

该方法会针对不同的对象返回不同的整数,这一般是通过将该对象的内部地址转换成一个整数

来实现的

用hashCode方法来验证this关键字

public class This02 {

    public static void main(String[] args) {

        Dog dog1 = new Dog("jack", 20);
        System.out.println("dog1的hashcode=" + dog1.hashCode());
        dog1.info();
    }
}

class Dog {

    String name;
    int age;
    /*
    如果我们构造器的形参,直接写成属性名,就比较好
    但是出现了一个问题,根据变量的作用域原则
    构造器的name / age就是局部变量,而不是属性
    */
    public Dog(String name, int age) {
        //this.name就是当前对象的属性name
        this.name = name;
        //this.age就是当前对象的属性age
        this.age = age;
        System.out.println("this.hashcode=" + this.hashCode());
    }

    public void info() {  //这里的name和age还是属性
        System.out.println(name + "\t" + age + "\t");
    }
}
/*
hashcode:返回该对象的哈希码值
该方法会针对不同的对象返回不同的整数,这一般是通过将该对象的内部地址转换成一个整数
来实现的
输出结果:
this.hashcode=366712642
dog1的hashcode=366712642
*/

this小结

哪个对象调用,this就代表哪个对象

注意事项和使用细节

  • 访问成员方法的语法:this.方法名(参数列表);

public class ThisDetail {

    public static void main(String[] args) {

        T t1 = new T();
        t1.f2();
        
    }
}

class T {

    //细节:访问成员方法的语法:this.方法名(参数列表);

    public void f1() {
        System.out.println("f1() 方法...");
    }

    public void f2() {
        System.out.println("f2() 方法...");
        //调用本类的f1方法
        //第一种方式
        this.f1();
        //第二种方式
        f1();
        //这两种方法是有区别的,在讲继承的时候会说

    }
}

输出

f2() 方法...
f1() 方法...
f1() 方法...
  • 访问构造器语法:this(参数列表),注意只能在构造器中使用(即只能在构造器中访问另外一个构造器)

public class ThisDetail {

    public static void main(String[] args) {

        // T t1 = new T();
        // t1.f2();
        T t2 = new T();

    }
}

class T {

    /*
    访问构造器语法:this(参数列表),必须放在第一条语句,注意只能在构造器中使用
    (即只能在构造器中访问另外一个构造器)
    */
    public T() {
        //访问T(String name, int age)构造器
        this("jack", 20);

        System.out.println("T() 构造器");

    }

    public T(String name, int age) {
        System.out.println("T(String name, int age) 构造器");
    }

    //细节:访问成员方法的语法:this.方法名(参数列表);

    public void f1() {
        System.out.println("f1() 方法...");
    }

    public void f2() {
        System.out.println("f2() 方法...");
        //调用本类的f1方法
        //第一种方式
        this.f1();
        //第二种方式
        f1();
        //这两种方法是有区别的,在讲继承的时候会说

    }
}

输出

T(String name, int age) 构造器
T() 构造器
  • this不能在类定义的外部使用,只能在类定义的方法中使用

作业题

  • 编写类A01,定义方法max,实现求某个double数组的最大值,并返回

/*
编写类A01,定义方法max,实现求某个double数组的最大值,并返回
*/
public class Homework01 {

    public static void main(String[] args) {

        double nums[] = {2.0, 0.2, 9.9, 3.25, 4.26};
        A01 a01 = new A01();
        Double res = a01.Findmax(nums);
        if(res != null) {
            System.out.println("最大的数为:");
            System.out.println(res);
        } else {
            System.out.println("输入有误");
        }
        
    }
}

class A01 {

    public Double Findmax(double... nums) {
        if(nums != null && nums.length > 0) {
            double MaxNum = nums[0];
            for( int i = 1; i < nums.length; i ++ ) {
                if(nums[i] > MaxNum) {
                    MaxNum = nums[i];
                }
            }
            return MaxNum;
        } else {
            return null;
        }
    }
}
/*
如果double nums[] = {2.0, 0.2, 9.9, 3.25, 4.26};
输出结果:9.9
为增强代码健壮性
如果double nums[] = {};
如果double nums[] = null;
*/

成员方法的接收采用Double类的方式,既可以接收一个double类型的变量,也可以接收null

  • 编写类A02,定义方法Find,实现查找某字符串是否在字符串数组中,并返回索引,如果找不到返回-1

/*
编写类A02,定义方法Find,实现查找某字符串是否在字符串数组中,并返回索引,如果找不到
返回-1
*/
public class Homework02 {

    public static void main(String[] args) {

        A02 a02 = new A02();
        String[] str = {"jack", "tom", "merry", "jone"};
        System.out.println(a02.Find("merry", str));
    }
}

class A02 {

    public int Find(String findstr, String[] str) {
        for( int i = 0; i < str.length; i ++ ) {
            if(findstr.equals(str[i])) 
                return i;
        }
        return -1;
    }
}
  • 编写类Book,定义方法updatePrice,实现更改某本书的价格,具体:如果价格>150,则更改为150;如果价格>100,则更改为100,否则不变

public class Homework03 {

    public static void main(String[] args) {

        book b = new book("悲惨世界", 128.5);
        b.updatePrice();
        b.info();
    }
}

class book {

    String name;
    double price;
    public book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public void updatePrice() {
        if(this.price > 150) {
            this.price = 150;
        } else if(this.price > 100) {
            this.price = 100;
        }
    }

    public void info() {
        System.out.println("书名:" + this.name + " 价格:" + this.price);
    }
}
  • 编写类A03,实现数组的复制功能copyArr,输入旧数组,返回一个新数组,元素和旧数组一样

public class Homework04 {

    public static void main(String[] args) {

        A03 a03 = new A03();
        int[] arr = {1, 2, 3, 4, 5};
        int[] newarr = a03.copyArr(arr);
        for( int i = 0; i < newarr.length; i ++ ) {
            System.out.print(newarr[i] + " ");
        }
    }
}

class A03 {

    public int[] copyArr(int[] arr) {

        int[] newarr = new int[arr.length];
        for( int i = 0; i < arr.length; i ++ ) {
            newarr[i] = arr[i];
        }
        return newarr;
    }
}
  • 定义一个圆类Circle,定义属性:半径,提供显示圆周长功能的方法,提供显示圆面积的方法

public class Homework05 {

    public static void main(String[] args) {

        Circle c = new Circle();

        System.out.println(c.perimeter(3.0));
        System.out.println(c.area(3.0));

    }
}

class Circle {

    double radius;
    public double perimeter(double radius) {
        return 2 * Math.PI * radius;
    }

    public double area(double radius) {
        return Math.PI * radius * radius;
    }

}
  • 编程创建一个Cale计算类,在其中定义2个变量表示两个操作数,定义四个方法实现求和、查、乘、商(要求除数为0的话,并提示),并创建两个对象,分别测试

public class Homework06 {

    public static void main(String[] args) {

        Cale cale = new Cale(2, 0);
        System.out.println("和=" + cale.add());
        System.out.println("差=" + cale.minus());
        System.out.println("乘=" + cale.mul());
        Double Divres = cale.div();
        if(Divres == null) {
            System.out.println("除数不能为0");
        } else {
            System.out.println("除=" + cale.div());
        }
        
    }
}

class Cale {

    double num1;
    double num2;
    public Cale(double num1, double num2) {
        this.num1 = num1;
        this.num2 = num2;
    }
    public double add() {
        return num1 + num2;
    }
    public double minus() {
        return num1 - num2;
    }
    public double mul() {
        return num1 * num2;
    }
    public Double div() {
        if(num2 == 0)
            return null;
        else
            return num1 / num2;
    }
}
  • 阅读以下代码,分析输出结果

10 9 10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AoXin_TechJZ.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值