Java基础自学记录六

面向对象编程基础

此为笔者个人笔记,如有错误还请指出

//例子一
public class Test{
    public static void main(String[] args){
        Cat cat1 = new Cat();
        cat1.name = "小白";
        cat1.color = "white";
        cat1.age = 2;
    }
}
class Cat{
    String name;
    String color;
    int age;
}

类信息只加载一次

在这里插入图片描述

属性与成员变量是一个意思

类的注意事项

  • 类的定义与变量类似,但多了一个访问修饰符 访问修饰符 属性类型 属性名

    • public
    • protected
    • 默认
    • private
  • 实行定义类型可以是任意类型

  • 创建的对象实际上是对象引用(可类比于人的名字)

创建对象的方式与访问方式

Cat cat = new Cat();
Cat cat;
cat = new Cat();

类与对象的内存分配机制

跟数组一样,拷贝时也是拷贝的地址,浅拷贝

public class Test{
    public static void main(String[] args){
        Person p1 = new Person();
        p1.name = "mio";
        p1.age = 2;
        p1.height = 3.3333;
        Person p2;
        p2 = p1;
        System.out.println(p2.name + "\t" + p2.age + "\t" + p2.height);
        p2.height = 4.33;
        System.out.println(p1.name + "\t" + p1.age + "\t" + p1.height);
        p2 = null;
        //System.out.println(p2.name + "\t" + p2.age + "\t" + p2.height);//仅p2指向了空,p1不改变,此行抛出异常
        System.out.println(p1.name + "\t" + p1.age + "\t" + p1.height);
    }
}
class Person{
    String name;
    double height;
    int age;
}

在这里插入图片描述

成员方法

class Person{
    String name;
    double height;
    int age;
    public void Speak(){
        System.out.println("I'm a good person");
    }
    public int cal01(int n = 1000){
        int sum = 0;
        for(int i = 1; i <= 1000; i++){
            sum+=i;
        }
        return sum;
    }
}

调用成员方法时会在栈空间创建一个栈,执行成员方法,成员方法执行结束返回后此栈消失,返回到调用的地方,返回后继续执行后续代码

成员方法的好处:提高代码复用性、将实现细节封装,供其他用户调用即可

成员方法的定义:

public 返回数据类型 方法名(参数列表) {
    //方法体
    //...
    return 返回值;//不是必须,由返回数据类型决定void就不用了(或者只写return;)
}

方法的使用细节

  • 访问修饰符(四种,控制访问权限)
  • 方法名的命名遵循驼峰命名法,最好见名知意
  • 一个方法最多有一个返回值
  • 一个方法可以有一个或者多个参数,方法类型可以是任意类型
  • 注意参数和传入类型的兼容性(传小不传大)
  • 方法定义时的参数称为形式参数,调用时的参数称为形式参数
  • 实参形参要顺序、个数、类型一致

  • 方法体中不能嵌套定义方法

方法调用细节

  • 同类中方法调用直接使用方法名即可
  • 跨类方法A调用B需要B.方法名(参数);

  • 跨类方法调用时注意方法的访问修饰符

练习题

public class Exercise{
    public static void main(String[] args){
        AA a = new AA();
        a.oOrJ(39876212);
        a.Print(34, 78, @);
        int c=10, d=20;
        a.Swap(c, d);//仍是10和20
    }
}
class AA{
    public boolean oOrJ(int a){
        //偶true奇false
        return a%2==0? true : false;
    }
    public void Print(int l, int r, char c){
        for(int i = 0; i < l; i++){
            for(int j = 0; j < r; j++){
                System.out.print(c+"\t");
            }
            System.out.println();
        }
    }
    public void Swap(int a, int b){
        int temp = a;
        a = b;
        b = temp;
    }
}

方法传参机制

parameter

调用方法时,会创建一个新栈,若在新栈中若不是引用类型的数据进行修改,此修改对调用处的两元素是没有效果的(形参无法影响实参)

若是数组、类等引用类型的数据,修改是有效的(传的是地址,可以通过形参影响实参)


public class Exercise{
    public static void main(String[] args){
        AA a = new AA();
        Person p = new Person();
        p.name="11";
        p.height=12.3;
        p.age=33;
        a.changePerson(p);
        System.out.println(p.age);
        //输出33,置空的只是方法栈中的指针,方法栈中修改Person的属性的值才会对main里面的p有作用
    }
}
class Person{
    String name;
    double height;
    int age;
}
class AA{
    public void changePerson(Person p){
        p = null;
        p = new Person();
        //同样不改变,开辟了新的对象,与之前的没关系了
    }
}

Exercise

public class Exercise{
    public static void main(String[] args){
        int[][] a = {{1, 2, 3, 4},
                     {2, 2, 3, 4},
                     {3, 3, 4, 3}};
        MyTools myTools = new MyTools();
        myTools.Print(a);
        Person p = new Person();
        p.name="11";
        p.height=12.3;
        p.age=33;
        Person q = myTools.copyPerson(p);
        System.out.println(p.age);
    }
}
class Person{
    String name;
    double height;
    int age;
}
class MyTools{
    public void Print(int[][] a){
        for(int[] i : a){
            for(int j : i){
                System.out.print(j+"\t");
            }
            System.out.println();
        }
    }
    public Person copyPerson(Person wt){
        Person ans = new Person();
        ans.name = wt.name;
        ans.height = wt.height;
        ans.age = wt.age;
        return ans;
    }
}

方法递归调用

  • 每执行一次方法,就创建一个新的受保护的独立空间

  • 方法的局部变量是独立的,不会互相影响(每次递归中相同的变量名)

  • 若使用的是引用类型的数据,则递归过程中会共享此引用类型数据

  • 递归时先写出口,避免无限递归

  • 遵守谁调用返回给谁的原则

Exercise

public class Exercise{
    public static void main(String[] args){
        MyTools m = new MyTools();
        int ans = m.Fab(7);
        System.out.println(ans);
        //没找的是0,障碍物是1,找过的是2,走不通的路是3
        int[][] mp = {{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}};
    }
}
class MyTools{
    //指引方向:下右上左
    int[][] tws = {{1,0},
                   {0,1},
                   {-1,0},
                   {0,-1}};
    //求出斐波那契数列的第n项
    public int Fab(int n){
        if(n == 1 || n == 2) return 1;
        return Fab(n - 1) + Fab(n - 2);
    }
    //猴子吃桃问题 n 天剩一个桃子 n-1剩4个桃吃3个  n为第一天,返回有多少个桃子
    public int Peach(int n){
        if(n == 2) return 4;
        //前一天的桃子数等于今天剩桃子数+1  *  2
        return (Peach(n - 1) + 1) * 2;
    }
    //小老鼠走迷宫
    public boolean findWay(int[][] mp, int x, int y){
        int x1, y1;
        if(mp[6][5] == 2) {
            return true;
        } else{
            if(mp[x][y] == 0){
                mp[x][y] = 2;//走过
                for(int i = 0; i < 4; i++){
                    x1 = x + tws[i][0];
                    y1 = y + tws[i][1];
                    if(findWay(mp, x1, y1)){
                        return true;
                    }//找到就true,没找到就换个方向找(有墙或标记了不通)
				   Print(mp);//打印当前路线,便于观察
				   System.out.println("========================");
                }
                mp[x][y] == 3; //四个方向都寄了,标记此路不通
			   return false;//四个都没走通,向上级返回false
            }else{ //mp[x][y]==1,2  障碍/走过
                return false;
            }
        }
    }
	//打印二维数组
	public void Print(int[][] a){
        for(int[] i : a){
            for(int j : i){
                System.out.print(j+"\t");
            }
            System.out.println();
        }
    }
    //汉诺塔问题,n个盘子,从a借助b移动到c
    public void Hannuota(int n, char a, char b, char c){
        //递归出口
        if(n == 1){
            System.out.println(a+"->"+c);
        }
        //先将n-1个借助c移动到b
        Hannuota(n - 1, a, c, b);
        //再第n个移动到c
        System.out.println(a+"->"+c);
        //再将b上的n-1个借助a移动到c
        Hannuota(n - 1, b, a, c);
    }
    //八皇后问题
    
    //思路:一个放在一行一列
    //第二个放在二行一列,判断是否满足(一定要考虑同一条斜线上的!!!),不满足就把所有列放完
    //依次进行每一个
    //得到一个正确的后回溯到第一个皇后放第二列,继续执行后续步骤
    //每个皇后的行都不变,只对列进行变化
    
    //判断是否可以放置在此位置的方法:
    private boolean isOk(int row, int target, int[] num){
        for(int i == 0; i < num.length; i++){
            //前面是横,后面是斜线
            if(num[i] = target || Math.abs(row - i) == Math.abs(target - num[i])){
                return false;
            }
        }
        return true;
    }
    //打印棋盘
    private void PrintQueens(int[] arr){
        for(int i = 0; i <arr.length; i++){
            for(int j = 0; j < arr.length; j++){
                if(j != arr[i]){
                    System.out.print("*");
                }else{
                    System.out.print("^");
                }
            }
            System.out.println();
        }
        System.out.println("========");
    }
    //记录解决方法数
    private long solves;
    //主函数
    public int Queens(int n){
        solves = 0;
        goQueens(0, new int[n]);
        return solves;
    }
    //用于递归的函数
    private void goQueens(int row, int[] ans){
        if(row == ans.length){
            solves++;
            PrintQueens(ans);
            return ;
        }else{
            for(int i = 0; i < ans.length; i++){
                if(isOk(row, i, ans)){
                    ans[row] = i;
                    goQueens(row + 1, ans);
                    ans[row] = 0;
                }
            }
        }
    }
}

方法重载介绍

同一个类中函数名同但功能不同

好处:减轻的起名和记名的麻烦

使用细节

  • 方法名必须相同
  • 形参列表必须不同(可以类型与顺序不同) 即使返回值类型不同,参数相同也不是重载
  • 返回类型可以相同也可以不同

可变参数的使用

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

语法:访问修饰符 返回类型 方法名(数据类型… 形参名);

使用可变参数时,可以视为数组

public class Learn{
    public static void main(String[] args){
        MyTools m = new MyTools();
        int ans = m.hecheng(2, 3, 5, 7, 9, 10);
        System.out.println("和是"+ans);
    }
}

class MyTools{
    public int sum(int... nums){
        int ans = 0;
        for(int i = 0; i < nums.length; i++){
            ans += nums[i];
        }
        return ans;
    }
    public int hecheng(int a1, int... nums){
        int sums = sum(nums);
        return a1 * sums;
    }
}

注意事项和使用细节

  • 可变参数的实参可以是0 or 多个

  • 实参可以是数组

  • 本质就是数组

  • 可变参数和普通参数一起作为形参,可变参数必须保证在最后

  • 一个形参列表中只能出现一个可变参数(万万不可多)

作用域

局部变量一般指成员方法中定义的变量

方法属性可以和局部变量同名,访问遵循就近原则

同一作用域中,两个局部变量不能重名

属性生命周期长,随对象的创建而创建,伴随着对象的死亡而死亡,局部变量生命周期短,随着代码块执行而创建,随着代码块结束而死亡

全局变量/属性可以加修饰符,局部变量不可以

全局变量可以被本类使用,局部变量只能在本类中对应的方法中使用

构造器(构造函数)

完成对新对象的初始化

方法名要和类名字一致

语法:

class MyTools{
    public MyTools(){
        System.out.println("正在使用构造器");
    }
    public int sum(int... nums){
        int ans = 0;
        for(int i = 0; i < nums.length; i++){
            ans += nums[i];
        }
        return ans;
    }
    public int hecheng(int a1, int... nums){
        int sums = sum(nums);
        return a1 * sums;
    }
}

注意

  • 构造器的修饰符可以默认,也可以是public protected private
  • 构造器没有返回值
  • 方法名和类名必须一样
  • 参数列表和成员方法的参数列表一样的规则
  • 构造器的调用由系统完成
  • 在创建对象的时候,系统会自动调用该类的构造器完成初始化
  • 如果程序员没有自定义构造方法,系统会自动给类生成一个默认无参数的构造方法,可以使用javap反编译看一下
  • 一旦定义了自己的构造器,默认构造器就失效了,除非显示定义一下 Person(){};
public class Learn{
    public static void main(String[] args){
        Person p1 = new Person("ylll", 19);
        System.out.println(p1);
    }
}
class Person{
    String name;
    int age;
    public Person(String pName, int pAge){
        name = pName;
        age = pAge;
        System.out.println("你好"+pAge+"岁的"+pName);
    }
}
class Dog{
    String name;
}

在这里插入图片描述

Exercise

public class Exercise{
    public static void main(String[] args){
        Person p1 = new Person();
        Person p2 = new Person("yll", 19);
        System.out.println("Hello! "+ p1.age+ "  "+ p1.name);
        System.out.println("Hello! "+ p2.age+ "  "+ p2.name);
    }
}
class Person{
    String name;
    int age;
    public Person(String pName, int pAge){
        name = pName;
        age = pAge;
        //System.out.println("你好"+pAge+"岁的"+pName);
    }
    public Person(){
        age = 18;
    }
}

对象创建流程分析

Person p = new Person("yll", 19);
class Person{
    String name;
    int age = 90;
    public Person(String pName, int pAge){
        name = pName;
        age = pAge;
        //System.out.println("你好"+pAge+"岁的"+pName);
    }
    public Person(){
        age = 18;
    }
}

先默认创建对象,而后再初始化,构造函数执行的是对象的初始化

  • 1、加载Person类信息(Person.class),只会加载一次
  • 2、在堆中分配空间(地址)
  • 3、完成对象初始化(默认初始化null 0 -> 显式初始化null 90 -> 构造器初始化yll 19)
  • 将对象在队中的地址返回对象名(或者叫对象的引用)

this关键字

JVM给每个对象分配this,代表当前对象,相当于一个指向自己的指针

为了将属性与成员方法进行区分,如果不加this,会把name和age视作局部变量

class Person{
    String name;
    int age = 90;
    public Person(String name, int age){
        //name = name;
        //age = age;
        this.name = name;
        this.age = age;
    }
}

可以通过hashCode()来判断是否是同一个值

public class Exercise{
    public static void main(String[] args){
        Person p = new Person("yll", 19);
        System.out.println("p.hashCode()="+p.hashCode());
        Person p1 = p;
        System.out.println("p1.hashCode()="+p1.hashCode());
    }
}

class Person{
    String name;
    int age = 90;
    public Person(String name, int age){
        //name = name;
        //age = age;
        this.name = name;
        this.age = age;
        System.out.println("this.hashCode()="+this.hashCode());
    }
}

在这里插入图片描述

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

注意事项

  • this用于区分类的属性和局部变量
  • 访问成员方法:this.方法名()
  • 访问构造器:this(参数列表) 注意只能在构造器中使用
  • this不能在类定义外使用,只能在类定义的方法中使用
public class Exercise{
    public static void main(String[] args){
        
    }
}

class Person{
    String name;
    int age;
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    public boolean compareTo(Person p){
        return this.name.equals(p.name) && this.age == p.age; 
    }
}

Homework

public class Homework{
    public static void main(String[] args){
        MyTools m = new MyTools();
        
        //1、
        double[] d1 = {1.4,2.5,3254.21,53436.232,1.34,777.77,12345.6,2324.3142,46436.2};
        double dmax = m.max(d1);
        System.out.println(dmax);
        
        //2、
        char[] ch1 = {'1', '2', 'y', 'm', 'x', 'l', '9', '0'};
        int index = m.find(ch1, 'y');//2
        System.out.println("下标是:"+index);
        
        //4、
        int[] i1 = {13,3,35,65,7,3,34,432,13,6,45,7,5};
        System.out.println("i1:");
        for(int i: i1){
            System.out.print(i+"\t");
        }
        System.out.println();        
        int[] i2 = m.copyArr(i1);
        System.out.println("i2:");
        for(int i: i2){
            System.out.print(i+"\t");
        }
        System.out.println();
    }
}
class MyTools{
    public double max(double[] nums){
        double max = nums[0];
        for(double num: nums){
            if(num > max) max = num;
        }
        return max;
    }
    public int find(char[] chs, char target){
        int ans = -1;
        for(int i = 0; i < chs.length; i++){
            if(chs[i] == target){
                ans = i;
                break;
            }
        }
        return ans;
    }
    public int[] copyArr(int[] old){
        int[] newArr = new int[old.length];
        for(int i = 0; i < old.length; i++){
            newArr[i] = old[i];
        }
        return newArr;
    }
}
public class Homework{
    public static void main(String[] args){
        Book b = new Book();
        b.price = 151;
        b.updatePrice();
        System.out.println("原价151,现价"+b.price);
        b.price = 111;
        b.updatePrice();
        System.out.println("原价111,现价"+b.price);
    }
}
class Book{
    double price;
    public void updatePrice(){
        if(price > 150) price = 150;
        else if(price > 100) price = 100;
        else ;
    }
}
public class Homework{
    public static void main(String[] args){
        Dog d = new Dog("ww", "blue", 3);
        d.show();
    }
}
class Dog{
    String name;
    String color;
    int age;
    public Dog(String name, String color, int age){
        this.name = name;
        this.color = color;
        this.age = age;
    }
    public void show(){
        System.out.println(color+"色的小狗名叫"+name+";今年"+age+"岁了");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值