【Java】韩顺平Java学习日志05——面向对象编程基础部分

本文介绍了Java中的类与对象概念,详细阐述了属性、成员变量、字段、创建对象、访问属性、内存分配机制,以及方法(包括成员方法、方法调用、递归、重载、可变参数和构造方法)的使用。此外,还讲解了作用域、this关键字和实例应用,如猜拳游戏。
摘要由CSDN通过智能技术生成


单独变量不利于数据的管理
数组对于数据类型体现不出来

类与对象

对象拥有行为和属性
某个类,是自己定义的数据类型,对象就是一个具体的实例
从类到对象:创建一个对象,实例化一个对象,把类实例化
Java最大的特点就是面向对象

class Cat{
String name;
int age;
}
Cat cat1=new Cat();//把创建的猫赋给cat1
cat1.name="a";
cat1.age=9;

类是抽象的,概念的,代表一类事物,比如人类,猫类,即是一种数据类型
对象是具体的,实际的代表一个具体的事物,即是实例
类是对象的模板,对象是类的一个个体,对应一个实例
对象和数组都是引用类型

对象在内存中的存在形式

对象存放在栈,指向一个地址,该地址是存放在堆中的属性;(在栈中的对象实际上是对象的引用,对象名)
属性存放在堆,里面的基本数据类型直接存放在堆区,字符串则存放在方法区的常量池里,堆里只存放字符串的地址(属性数据等创建的对象空间才是真正的对象)
在这里插入图片描述
在执行new语句创建对象时,会把类信息加载到方法区,而后进行分配空间

在这里插入图片描述

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

属性是类的一个组成部分,可以时基本数据类型,也可以是引用类型(对象,数组)

细节说明

1.属性的定义语法与变量相同,但是增加了访问修饰符(控制属性的访问范围,共4种 public protected 默认 private)
格式:访问修饰符 属性类型 属性名
2.属性可以定义任意类型
3.属性如果不赋值,有默认值,规则和数组一致
在这里插入图片描述

创建对象和访问属性

创建对象

1.先声明再创建

Cat cat;//此时空间尚未分配
cat =new Cat();

2.直接创建

Cat cat=new Cat();
访问属性

对象名.name

内存分配机制

在这里插入图片描述

Java内存的结构分析

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

流程简单分析


在这里插入图片描述

成员方法(方法)

类的行为
访问范围 返回值 方法名(形参列表){方法体}
方法写好后如果不去调用不会生效输出结果
先创建对象,再调用方法:对象名.方法

方法调用总结

在这里插入图片描述
1.当程序执行到方法时,就会开辟一个独立的空间
2.当方法执行完毕,或者执行到return语句时,就会返回
3.返回到调用方法的位置
4.返回后,继续执行方法后面的代码
5.完全执行完毕后main方法栈执行完毕,整个程序退出

创建一个类,将方法写入该类,使用时方法时创建类的对象,用对象调用成员方法即可

成员方法的好处

1.提高代码的复用性
2.可以将实现的细节封装起来,然后供其他用户来调用即可

定义

访问修饰符 返回数据类型 方法名(形参列表){
//方法体语句
return 返回值;
}
1.形参列表:表示成员方法输入 cai(int n)
2.数据类型(返回类型):表示成员方阿飞输出,void表示没有返回值
3.方法主体:表示为了实现某一功能代码块
4.return语句不是必须的

注意细节

访问修饰符:控制方法使用的范围,如果不写默认访问

返回数据类型:
1.一个方法最多只能有一个返回值,如果是多个返回值可以选择返回 数组
2.返回类型可以是任意类型,包括基本类型或者引用类型
3.如果方法要求有返回数据类型,则方法体最后一句必须为return 值,而且要求返回值类型必须和return的值类型一致或兼容
4.如果方法是void,则方法中可以某一return语句,或者只写return

方法名:
遵循驼峰命名法,方法名要有一定含义,注意开发规范

形参列表:
1.一个方法可以有0哥参数,也可以有多个参数,中间用逗号隔开
2.参数类型可以为任意类型,包含基本类型或引用类型
3.调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数
4.方法定义时的参数称为形式参数,方法调用是参数为实际参数,实参和形参的类型要一致或兼容,个数和顺序必须一致

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

方法细节调用说明:
1.同一个类中的方法调用:直接调用即可
2.跨类中的方法A类调用B类方法:需要通过对象名调用:对象名.方法名(参数)
先创建B类对象,然后再调用
3.跨类调用和方法的访问修饰符相关
4.方法调用会产生新栈

成员方法传参机制

基本数据类型的传参机制
在这里插入图片描述
基本数据传递的是值(值拷贝吗,在方法的栈中再生成一份),形参的任何改变不影响实参

基本数据类型的传参机制:
在这里插入图片描述
引用类型传递的是地址(传递的也是值,但是值是地址),可以通过形参影响实参

特殊实例:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

方法的递归调用

递归的实例:

在这里插入图片描述
在这里插入图片描述

递归的重要规则

1.执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
2.方法的局部变量是独立的,不会相互影响
3.如果方法种使用的数引用类型变量(比如数组,对象),就会共享该引用类型
4.递归必须向退出递归的条件逼近,否则就是无限递归
5.当应该方法执行完毕,或者遇到return,就会返回,遵守谁调用就将结果返回谁,同时方法释放空间的控制器权和分配权

迷宫问题
import java.awt.image.ImageProducer;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        int[][] map = new int[8][7];
        for (int i = 0; i < 7; i++) {
            map[0][i] = 1;
            map[7][i] = 1;
        }
        for (int i = 0; i < 8; i++) {
            map[i][0] = 1;
            map[i][6] = 1;
        }
        map[3][1] = 1;
        map[3][2] = 1;
    }
    T t1=new T();
    t1.findWay(map,1,1);

}
class T{
    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;
            }
        }
    }
}
汉诺塔
import java.util.*;
public class Main {
    public static void main(String[] args) {
      T tower=  new T();
      tower.move(5,'A','B','C');
    }
}
class T{
    public void move(int num,char a,char b,char c){
        if(num==1){
            System.out.println(a+"->"+c);
        }else{
            //可以看成两个,最下面的和上面的所有(num-1)
            //先移动上面所有的盘到b,借助c
            move(num-1,a,c,b);
            //把最下面的盘移动到c
            System.out.println(a+"->"+c);
            //再把b的所有移动到c,借助a
            move(num-1,b,a,c);
        }
    }
}

运行结果:

A->C
A->B
C->B
A->C
B->A
B->C
A->C
八皇后问题

方法重载

Java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致
方法重载减轻了起名,记名的麻烦

使用细节

1.方法名必须相同
2.形参列表必须不同(参数的类型,个数或顺序,至少有一样不同,参数名无要求)
3.返回类型没有要求

在这里插入图片描述
方法重载也存在自动转换类型,但是无需自动转换类型的优先级更高

可变参数

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

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

使用可变参数时,可以当作数组来使用(遍历)

class Test{
    public int sum(int... nums){
     //可以接收多个int 遍历
        int res=0;
        for(int i=0;i<nums.length;i++)
        {
            res+=nums[i];
            return res;
        }

    }

}

使用细节

1.可变参数的实参可以为0或者任意多个
2.可变参数的实参可以为数组
3.可变参数的本质就是数组
4.可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
5.一个形参列表中国只能出现一个可变参数

实例:

class Test{
    public String show(String name,double... nums)
    {
        int res=0;
        for(int i=0;i<nums.length;i++)
        {
            res+=nums[i];
        }
        return name+"成绩:"+res;
    }

}

作用域

1.Java中主要的变量就是属性(成员变量)和局部变量
2.局部变量一般是指在成员方法中定义的变量
3.Java作用域的分类:
全局变量:也就是属性,作用域为整个类体
局部变量:也是除了属性之外的其他变量,作用域为定义它的代码块
4.全局变量(属性)可以不赋值,直接使用,因为有默认值,局本部变量必须赋值后才能使用,因为没有默认值
5.属性在定义时可以直接赋值

使用细节

1.属性和局部变量可以重名,访问时遵循就近原则
2.在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名(重复定义变量)
3.属性生命周期较长,伴随着对象的创建而创建,伴随着对象的死亡而死亡,局部变量生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而死亡,即在一次方法调用过程中
4.作用域不同:全局变量可以被本类使用,或被其他类使用(通过对象调用),局部变量只能在本类中对应的方法使用
5.修饰符不同:全局变量可以加修饰符,局部变量不可以加修饰符

构造方法/构造器

修饰符 方法名(形参列表){方法体}
1.构造器的修饰符可以默认,也可以时public private protected
2.构造器没有返回值,也不能写void‘
3.方法名必须和类名一样
4.参数列表和成员方法一致
5.构造器的调用,由系统完成

构造方法时类的一种特殊方法,主要作用是完成对新对象的初始化
1.方法名和类名相同
2.没有返回值
3.创建对象时,系统会自动的调用该类的构造器完成对象的初始化

使用细节

1.一个类可以定义多个不同的构造器,即构造器重载
2.构造器时完成对对象的初始化,不是创建对象
3.如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造方法(默认构造方法)
4.一旦定义了自己的构造器,默认的构造器就被覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下默认无参构造器

javap能对给定的class文件提供字节代码进行反编译
javap -c -v 类名
每创建一个对象,都要调用构造函数,都要开辟一个新空间

流程分析:
创建对象
先默认初始化
再进行显式初始化
构造器处理进行属性初始化
返回对象的地址
(对象实际在堆里,命名是对象的引用)
在这里插入图片描述
1.加载Person类信息,只会加载一次
2.在堆中分配空间(地址)
3.完成对象的初始化(默认初始化,显示初始化,构造器初始化)
4.对象在堆中的地址返回给p,p是对象名也可以理解成对象的引用

this关键字

Java虚拟机会给每个对象分配this,代表当前对象
在这里插入图片描述
哪个对象调用,this就代表哪个对象
在这里插入图片描述
验证:hashCode方法会针对不同的对象返回不同的整数(将对象的内部地址转换成一个整数来实现的)

使用细节

1.this关键字可以用来访问本类的属性,方法,构造器
2.this用于区分当前类的属性和局部局部变量
3.访问成员方法语法:this.方法名(形参列表)

class T{
    //访问成员方法的语法:this.方法名(参数列表)
    public void f1(){
        System.out.println("f1");
    }
    public void f2(){
        System.out.println("f2");
        //调用本类的f1
        //第一种方式
        f1();
        //第二种方式
        this.f1();
    }
}

4.访问构造器语法:this(参数列表),只能在构造器中使用(只能在构造器中访问另外一个构造器,必须放在第一条语句)

public T(){
        //访问T(String,int)
        this("jack",100);
        System.out.println("T() 构造器");
    }
    public T(String name,int age){
        System.out.println("T(String,int) 构造器");
    }
}
//注意:访问构造器语法this必须放在构造器的第一条语句

5.this不能在类定义的外部使用,只能在类定义的方法中使用

注意:访问区别
在这里插入图片描述

实例:
import java.util.*;
public class Main{
    public static void main(String[] args) {
        Person p1=new Person("mary",12);
        Person p2=new Person("mary",12);
        System.out.println("比较结果:"+p1.compareTo(p2));
    }
}
class Test{

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

运行结果:

比较结果:true

注意

任何类都可以有main
匿名对象只能使用一次,使用过后即销毁

实例作业

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
但是只能用一个,因为在构造器中访问另一个构造器的this语句必须放在第一句

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Circle c=new Circle();
        PassObject po=new PassObject();
        po.printAreas(c,5);
    }
}
class Circle{
    double radius;
    public Circle(){}
    public Circle(double radius)
    {
        this.radius=radius;
    }

    public double findArea()
    {
        return Math.PI*radius*radius;
    }
    public void setRadius(double radius)
    {
        this.radius=radius;
    }
}
class PassObject{
    public void printAreas(Circle c,int times)
    {
        System.out.println("radius\tarea");
        for(int i=1;i<=times;i++)
        {
            c.setRadius(i);
            System.out.println((double)i+"\t"+c.findArea());

        }
    }
}
猜拳游戏
import java.util.*;
public class Main {
    public static void main(String[] args) throws IllegalAccessException {
        Tom t=new Tom();
        int isWinCount=0;
        int[][] arr1=new int[3][3];
        int j=0;
        String[] arr2=new String[3];
        Scanner sc=new Scanner(System.in);
        for(int i=0;i<3;i++)
        {
            System.out.println("请输入你要出的拳:");
            int num=sc.nextInt();
            t.setTomNum(num);
            int tomGuess=t.getTomNum();
            arr1[i][j+1]=tomGuess;

            int comGuess=t.computerNum();
            arr1[i][j+2]=comGuess;

            String isWin=t.vsComputer();
            arr2[i]=isWin;
            arr1[i][j]=t.count;

            System.out.println(t.count+"\t"+tomGuess+"\t\t"+comGuess+"\t\t");
            isWinCount=t.winCount(isWin);
        }
        for(int a=0;a<arr1.length;a++)
        {
            for(int b=0;b<arr1[a].length;b++)
            {
                System.out.print(arr1[a][b]+"\t\t\t");
            }
            System.out.print(arr2[a]);
            System.out.println();
        }
        System.out.println("you win"+isWinCount);
    }
}
class Tom{
    int tomNum;
    int comNum;
    int winCount;
    int count=1;
    public void showInfo(){

    }
    public int computerNum(){
        Random r=new Random();
        comNum=r.nextInt(3);//返回0-2的随机数
        return comNum;
    }
    public void setTomNum(int tomNum) throws IllegalAccessException {
        if(tomNum>2||tomNum<0){
            throw new IllegalAccessException("数字输入错误");
        }
        this.tomNum=tomNum;
    }

    public int getTomNum() {
        return tomNum;
    }

    public String vsComputer(){
        if(tomNum==0&&comNum==1){
            return "you win";
        }else if(tomNum==1&&comNum==2)
        {
            return "you win";
        }else if(tomNum==2&&comNum==0)
        {
            return "you win";
        } else if (tomNum==comNum) {
            return "平局";
        }else
            return "you false";
    }
    public int winCount(String s){
        count++;
        if(s.equals("you win")){
            winCount++;
        }
        return winCount;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值