坚定不移学Java-Day05

 整理自 韩顺平零基础30天学Java

【零基础 快速学Java】韩顺平 零基础30天学会Java_哔哩哔哩_bilibili

类与对象

对象的分配机制

Person p1 = new Person();
p1.age = 10;
p1.name = "小明";
Person p2 = p1; //把p1赋给了p2,或让p2指向p1
System.out.println(p2.age); //10

内存的结构分析

  1. 栈:一般存放基本数据类型(局部变量)。
  2. 堆:存放对象(Cat cat,数组等)。
  3. 方法区:常量池(常量,比如字符串),类加载信息。
  4. 示意图 [Cat (name, age, price)]

创建对象的流程

Person p = new Person();
p.name = "jack";
p.age = 10;
  1. 加载Person类信息(属性和方法信息,只会加载一次)
  2. 在堆中分配空间,进行默认初始化。
  3. 把堆中的地址赋给p,p指向对象。
  4. 进行指定初始化。

练习 

Person a = new Person();
a.age = 10;
a.name = "小明";
Person b;
b = a;
System.out.Println(b.name); //小明
b.age = 200;
b = null; //将b所存的地址置空
System.out.Println(a.age); //200
System.out.Println(b.age); //异常

成员方法

public class D5 {
    public static void main(String[] args) {
        Person person = new Person();
        person.speak();
        person.cal01();
        person.cal02(10);
        int sum = person.getSum(40,50);
        System.out.println("计算结果=" + sum);
    }
}

class Person{
    String name;
    int age;
    public void speak(){
        System.out.println("I'm a nice guy.");
    }
    public void cal01(){
        int res = 0;
        for (int i = 0; i <= 100; i++){
            res += i;
        }
        System.out.println("计算结果=" + res);
    }
    public void cal02(int n){
        int res = 0;
        for (int i = 0; i <=n; i++){
            res +=i;
        }
        System.out.println("计算结果=" + res);
    }
    public int getSum(int num1,int num2){
        int res = num1 + num2;
        return res;
    }
}

调用机制

  1. 当程序执行到方法时,就会开辟一个独立的(栈)空间。
  2. 当方法执行完毕,或执行到return语句时,就会返回。
  3. 返回到调用方法的地方,继续执行方法后面的代码。
  4. 当main方法(栈)执行完毕,整个程序退出。
好处
  1. 提高代码的复用性。
  2. 可以将实现的细节封装起来,供其他用户来调用即可。(工作之后做项目开发时)

定义

访问修饰符 返回数据类型 方法名 (形参列表){

        语句;

        return 返回值;    //不是必须的

}

 细节

访问修饰符

作用:控制方法使用的范围。

有:public、protected、private、默认。如果不写,默认访问。

返回类型
  1. 一个方法最多有一个返回值。(返回数组,可以实现返回多个值)
  2. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)。
  3. 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为return值;而且要求返回值类型必须和return的值类型一致或兼容。
  4. 如果方法是void,则方法体中可以没有return语句,或者只写 return;
方法名

驼峰命名法,见名知义。如getSum

形参列表
  1. 一个方法可以有0个参数,也可以有多个参数,中间用逗号隔开。比如getSum(int n1, int n2)。
  2. 参数类型可以为任意类型,包含基本类型或引用类型。比如printArr(int[][] map)。
  3. 调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数。
  4. 方法定义时的参数称为形式参数,简称形参;方法调用时的参数称为实际参数,简称实参。实参和形参的类型要一致或兼容,个数、顺序必须一致。
方法体

里面写完成功能的具体语句,可以为输入、输出、变量、运算、分支、循环、方法调用,但是不能再定义方法。即不能嵌套。

方法细节的调用说明
  1. 同一个类中:直接调用即可。
  2. 跨类的方法A类调用B类方法:需要通过对象名调用。e.g.对象名.方法名(参数);
    跨类的方法调用和方法的访问修饰符相关。

传参机制

除byte,short,int,long,char,boolean,float,double外,其余都是引用数据类型。

基本数据类型
public class D5 {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        AA obj = new AA();
        obj.swap(a, b);
        System.out.println("a=" + a + "b=" + b);  // 10 20
    }
}
class AA{
    public void swap(int a, int b){
        System.out.println("a和b交换前的值\na=" + a + "\tb=" + b) // 10 20
        int tmp = a;
        a = b;
        b = tmp;
        System.out.println("a和b交换后的值\na=" + a + "\tb=" + b) //20 10
    }
}

 基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参。

引用数据类型
public class D5 {
    public static void main(String[] args) {
        B b = new B();
        int[] arr = {1, 2, 3};
        b.test100(arr);
        System.out.println("main方法中的数组");
        for (int i = 0; i < arr.length; i++){
            System.out.print(arr[i] + "\t"); //200 2 3
        }
        System.out.println();
    }
}
class B{
    public void test100(int[] arr){
       arr[0] = 200;
       System.out.println("test100方法中的数组");
       for (int i = 0; i < arr.length; i++){
            System.out.print(arr[i] + "\t"); //200 2 3
       }
       System.out.println();
    }
}

引用数据类型,传递的是地址(地址拷贝),可以通过形参影响实参。

克隆对象
public class D5 {
    public static void main(String[] args) {
//        克隆对象
        Person p = new Person();
        p.name = "milan";
        p.age = 30;
        MyTools tools = new MyTools();
        Person p2 = tools.copyPerson(p);
//        p和p2是Person对象,但是是两个独立的对象,属性相同
        System.out.println("p的属性 age=" + p.age + "名字 name=" + p.name);
        System.out.println("p2的属性 age=" + p2.age + "名字 name=" + p2.name);
//        可以通过输出对象的hashCode看看对象是否是同一个 或 通过对象比较看看是不是同一个
        System.out.println(p == p2);
    }
}

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;
    }
}

递归调用

递归:方法自己调用自己,每次调用时传入不同的变量。递归有助于编程者解决复杂问题,同时可以让代码变得简洁。

那迭代呢?两者有差别吗?

阶乘
public class D5 {
    public static void main(String[] args) {
//        阶乘
        T t1 = new T();
        int res = t1.factorial(5);
        System.out.println("res=" + res);
    }
}

class T{
    public int factorial(int n){
        if (n == 1){
            return 1;
        }else {
            return factorial(n - 1) * n;
        }
    }
}
规则
  1. 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)。
  2. 方法的局部变量是独立的,不会相互影响。
  3. 如果方法中使用的是引用类型变量(比如数组、对象),就会共享该引用类型的数据。
  4. 递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError(死鬼)。
  5. 当一个方法执行完毕,或者遇到return,就会返回,遵守“谁调用就将结果返回谁”。同时当方法执行完毕或者返回时,该方法也就执行完毕。
习题
斐波拉契数
public class D5 {
    public static void main(String[] args) {
//        斐波那契数列1,1,2,3,5,8,13...
        F f = new F();
        int res = f.fibonacci(9);
        if(res != -1){
            System.out.println("当n=7时,对应的斐波那契数是:"+ res);
        }else{
            System.out.println("输入的数字有误");
        }
    }
}
class F{
    public int fibonacci(int n){
        if (n >= 1){
            if(n == 1 || n == 2){
                return 1;
            }else{
                return fibonacci(n-1) + fibonacci(n-2);
            }
        }else{
            return -1;
        }
    }
}

从确切的数据入手找规律!

老鼠走迷宫
package chapter01;

import com.sun.source.tree.NewArrayTree;

public class MiGong {
    public static void main(String[] args) {
//        1.创建迷宫,用二维数组表示 int[][] map = new int[8][7];
//        2.先规定 map 数组的元素值:0表示可以走;1表示障碍物
        int[][] map = new int[8][7];
//        3.将最上面和最下面的两行设置为1
        for(int i = 0; i < 7; i++){
            map[0][i] = 1;
            map[7][i] = 1;
        }
//        4.最左和最右两列也要置成1
        for(int i = 0;i < 8; i++){
            map[i][0] = 1;
            map[i][6] = 1;
        }
//        5.[3,1]和[3,2]也是障碍
        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();
        }
//        使用findWay给老鼠找路
        Mouse mouse = new Mouse();
        mouse.findWay(map,1,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();
        }
    }
}
class Mouse {
//    使用递归回溯
//    i,j是老鼠的位置,初始位置为(1,1)
//    规定:map数组各个值的含义
//    0:可以走,未测试,1:障碍物,2:可以走,已测试,3:走过,但走不通
//    当 map[6][5] == 2,就说明找到通路了退出,否则就继续找
//    确定老鼠找路的策略:下 右 上 左
    public boolean findWay(int[][] map, int i, int j){
        if (map[6][5] == 2){
            return true;
        }else{
            if (map[i][j] == 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;
            }
        }
    }
}
汉诺塔
package chapter01;

public class HanoiTower {
    public static void main(String[] args) {
        Tower tower = new Tower();
        tower.move(5, 'A', 'B', 'C');
    }
}
class Tower{
    public void move(int num, char a, char b, char c){
//        如果只有一个盘
        if (num == 1){
            System.out.println(a + "->" + c);
        }else {  //如果有多个盘,可以看成两个盘:最下面的 和 上面的所有盘
//            先移动上面所有的盘到 b,借助 c
            move(num - 1, a, c, b);
//            最下面的盘,移动到c
            System.out.println(a + "->" + c);
//            再把 b塔的所有盘移动到 c,借助 a
            move(num - 1, b, a, c);
        }
    }
}

方法重载(OverLoad)

Java中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致(类型、个数、顺序),形参命名、返回类型无所谓。

比如:System.out.println(100);   System.out.println("hello");    System.out.println('h');
out是PrintStream类型。

好处
  1. 减轻了起名的麻烦。
  2. 减轻了记名的麻烦。
package chapter01;

import java.util.Scanner;

public class D5 {
    public static void main(String[] args) {
        MyCalculator myCalculator = new MyCalculator();
        System.out.println(myCalculator.calculate(1, 2));
        System.out.println(myCalculator.calculate(1.0,2));
        System.out.println(myCalculator.calculate(1, 2.0));
        System.out.println(myCalculator.calculate(1, 2, 3));
    }
}

//重载
class MyCalculator{
    public int calculate(int n1, int n2){
        return n1 + n2;
    }
    public double calculate(int n1, double n2){
        return n1 + n2;
    }
    public double calculate(double n2, int n1){
        return n1 + n2;
    }
    public int calculate(int n1, int n2, int n3){
        return n1 + n2 + n3;
    }
}
习题

巧用三目运算符,减少代码量。

package chapter01;

import java.util.Scanner;

public class D5 {
    public static void main(String[] args) {
//        重载2
        Methods methods = new Methods();
        methods.m(2);
        methods.m(3,4);
        methods.m("Let's do it! DuoRuimi");
//        重载3
        System.out.println(methods.max(1,2));
        System.out.println(methods.max(1.0,2.0));
        System.out.println(methods.max(1.0,2.0,3.0));
    }
}

class Methods{
    public void m (int n){
        System.out.println(n * n);
    }
    public void m (int n1, int n2){
        System.out.println(n1 * n2);
    }
    public void m (String n){
        System.out.println(n);
    }
    public int max(int n1, int n2){
//        if (n1 < n2){
//            return n2;
//        }else{
//            return n1;
//        }
        return  n1 > n2 ? n1 : n2;
    }
    public double max(double n1, double n2){
//        if (n1 < n2){
//            return n2;
//        }else{
//            return n1;
//        }
        return  n1 > n2 ? n1 : n2;
    }
    public double max(double n1, double n2, double n3){
//        if (n1 > n2){
//            if (n3 >n1){return n3;}
//            return n1;
//        }else {
//            if (n3 >n2){return n3;}
//            return n2;
//        }
        double max1 = n1 > n2 ? n1 : n2;
        return max1 > n3 ? max1 : n3;
    }
}

可变参数

Java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。

访问修饰符 返回类型 方法名(数据类型... 形参名){

}

package chapter01;

import java.util.Scanner;

public class D5 {
    public static void main(String[] args) {
//        可变参数
        HspMethod hspMethod = new HspMethod();
        System.out.println(hspMethod.sum(1,2,4));
    }
}

class HspMethod {
//    int... 可以接收0-多个int
//    使用时,可以当作数组来使用
    public int sum (int... nums){
        int sum = 0;
        for (int i = 0; i < nums.length; i++){
            sum += nums[i];
        }
        return sum;
    }
}
细节
  1. 可变参数的实参可以为0个或任意多个。
  2. 可变参数的实参可以为数组。
  3. 可变参数的本质就是数组。
  4. 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后。
  5. 一个形参列表中只能出现一个可变参数。
  • 33
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值