类与对象java

类与对象

public class demo{
    public static void main(String[] args) {  

        //创建对象
        cat cat1 = new cat();
        cat1.name = "mike";
        cat1.age = 12;
        cat1.color = "rad";
        System.out.println(cat1.name);   
    }
}

class cat{

    //属性/成员变量 field字段
    String name;
    int age;
    String color;
}

内存

截屏2021-09-26 上午3.11.51.png

注意事项

  • 属性的定义语法同变量 :访问修饰符 属性类型 变量名

成员方法

public class demo{
    public static void main(String[] args) {  

        //创建对象
        cat cat1 = new cat();
        cat1.name = "mike";
        cat1.age = 12;
        cat1.color = "rad";

        cat1.speak();
        System.out.println(cat1.name);   
    }
}

class cat{

    //属性/成员变量 field字段
    String name;
    int age;
    String color;
    public void speak(){

    system.out.println("gogo");

}
}

方法调用机制

在这里插入图片描述

访问修饰符

作用是控制方法的使用范围

如果不写 默认访问(public,protected,默认,private)

返回数据类型

  • 一个方法最多有一个返回类型

  • 返回类型可以为任意类型

形参列表

方法定义时的参数称为形式参数,简称形参;方法调用时的传入参数称为实际参数,简称为实参。实参和形参的类型要一致或兼容、个数、顺序必须一致。

同类方法直接调用

public class Method01{
    public static void main(String args[]){
        A a = new A();
        a.sayOk();        
    } 
}

class A {
    public void print(int n){
        System.out.println(n+" ");
    }
    public void sayOk(){
        print(10);
        B b = new B();
        b.going();
        System.out.println("go");
    }
}

class B{
    public void going (){
        System.out.println("B is running");
    }
}

成员方法传参机制

引用类型传递的是地址

和C++指针差不多

public class MethodP{

    public static void main(String[] args) {
        // int a = 10 ;
        // int b = 20;

        A test = new A();
        person p = new person();
        p.age = 100;
        p.name = "Mike";
        test.test(p);
        System.out.println(p.age); //99
    }
}
class person{
    String name;
    int age;
}
class A{
    public void test(person p){
        p.age = 99;
        p = null;
    }
}
public class MethodP{

    public static void main(String[] args) {
        // int a = 10 ;
        // int b = 20;

        A test = new A();
        person p = new person();
        p.age = 100;
        p.name = "Mike";
        test.test(p);
        System.out.println(p.age);//100
    }
}
class person{
    String name;
    int age;
}
class A{
    public void test(person p){
   //     p.age = 99;
        p = null;
    }
}

递归

在这里插入图片描述

public class dfs{
    public static void main(String[] args) {
        int map[][] = new int[5][6]; 
        for(int i = 0;i<6;i++){
            map[0][i] = 1;
            map[4][i] = 1;
        }
        for(int i = 0;i<5;i++){
            map[i][0] = 1;
            map[i][5] = 1;
        }
        map[2][1] = 1;
        map[2][2] = 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.print("\n");
        }
        sumAcc test = new sumAcc();
        test.DFS(map,1,1,0);
        System.out.println(test.sum);
    }
}

class sumAcc{
    int sum = 0;
    int indexMap[][] = new int [5][6];
    int zou[][]  = {{1,0},{0,1},{-1,0},{0,-1}};
    public void DFS(int map[][],int i, int j,int t){
        // indexMap[i][j]=1;
        if(i==3&&j==4){
            sum++;
            return;
        }
        // System.out.println(i+" "+j);
        for(int k = 0;k<4;k++){
            if((i+zou[k][0]<5)&&(i+zou[k][0]>0)&&(j+zou[k][1]>0)&&(j+zou[k][1]<6)&&(indexMap[i+zou[k][0]][j+zou[k][1]]==0)&&(map[i+zou[k][0]][j+zou[k][1]]==0)){
                indexMap[i+zou[k][0]][j+zou[k][1]]=1;
                // System.out.println(t);
                DFS(map,i+zou[k][0],j+zou[k][1],t++);
                indexMap[i+zou[k][0]][j+zou[k][1]]=0;
            }
        }
    } 
}
// 汉诺塔
public class hanTower{
    public static void main(String[] args) {
        Tower tower = new Tower();
        tower.move(2,'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{
            move(num-1, a ,c , b);
            System.out.println(a + "->" + c);
            move(num-1,b,a,c);
        }
    }
}

重载

java中允许多个方法存在,通过传递的参数不同来调用合适的方法。和C++一样。

方法名:必须相同

形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)

返回类型:无要求

public void method(int a,int b){
    ...
}
public int method(int a,int c){
    ....
}
//错误使用,返回类型并无要求 两者传的参数一样,导致错误

可变参数

java允许将同种方法,多个参数的调用

使用可变参数时,可以当作数组来使用。

public class varParameter{
    public static void main(String[] args) {
        var v = new var();
        System.out.println(v.sum(1,2,3));
    }
}

class var{
    public int sum(int... nums){
        int res = 0;
        for(int i = 0;i < nums.length; i++){
            res += nums[i];
        }
        return res;
    }
}
  • 可变参数的实参个数是0或者多个

  • 可变参数的实参可以是数组

  • 可变参数的本质就是数组

  • 可变参数可以和普通参数一起在形参列表,但是可变参数需要在最后

作用域

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

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

  • java中的作用域的分类

    • 全局变量:属性,作用域为整个类体

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

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

属性和变量可以重名,就近原则。

作用域范围不同

全局变量可以被本类调用,也可以被其他类调用。

局部变量只可以被本类的方法访问。

属性可以加修饰符

局部变量不能加修饰符

构造器/构造方法

[修饰符]方法名(形参列表){

 方法体

}
  • 构造器的修饰符可以默认,也可以是public…

  • 构造器没有返回值

  • 方法名和类名字必须一样

  • 参数列表和成员一样的规则

  • 构造器的调用系统完成

构造方法又叫构造器,是类的一种特殊的方法。它的主要作用是完成对新对象的初始化

  • 方法名和类相同

  • 没有返回值

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

细节

  • 一个类可以定义多个不同的构造器,即构造器重载

  • 构造器名和类名相同

  • 构造器没有返回值

  • 构造器是完成对象的初始化,并不是创建对象。

  • 在创建对象时,系统自动调用该类的构造方法。

  • 如果程序员没有定义定义构造器,系统会自动给类生成一个默认的无参构造器(默认构造器)

    • class Dog{
          Dog(){
          }//系统创建的默认构造器
      }
      
public class Construct{
    public static void main(String[] args) {
        Person p1 = new Person("mike", 12);
        System.out.println(p1.name);

       //  Person p = new Person();
       // p.name = "mike"; 错的
    }
}

class Person{
    String name;
    int age;
    public Person(String Pname,int Page){
        name = Pname;
        age = Page;
    }
    public Person(String Pname){
        name = Pname;
    }
}

javap反汇编

流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1eYegGBe-1647795839394)(/Users/zhaofei/Desktop/截图/截屏2021-10-03%20上午4.00.36.png)]

流程分析

1.加载Person类信息,只会加载一次

2.在堆中分配空间

3.完成对象初始化【1.默认初始化 age=0,name = null,显示初始化 age = 90 name =null,构造器初始化 name= 小倩 age=20】

4.在对象在堆中的地址返回给p

this 关键字

this 就是指向当前对象。this就是哪个对象调用,就指向哪个对象

public class this{
    public static void main(String[] args) {
        Person p1 = new Person("mike", 12);
        System.out.println(p1.name);
    }
}

class Person{
    String name;
    int age;
    public Person(String name,int age){
        name = name;//name指的是局部变量构造器的
        age = age;//age同理 

        this.name = name ;
        this.age = age; //this就指向对象的属性
    }
    public Person(String Pname){
        name = Pname;
    }
}

使用细节

  • this关键字可以用来访问本类的属性、方法、构造器

  • this用于区分当前类的属性和局部变量

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

  • this构造器语法:this(参数列表);只能在构造器中使用

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

class T{
    public void f1(){
        System.out.println("f1");
    }
    public void f2(){
        System.out.println("f2");
        f1();
        this.f2();
    }
}
class T1{
    /*
    细节:访问构造器语法:this(参数列表)
    只能在构造器中使用,
    必须放置在第一条语句
    */
    String name;
    int age;
    public T1(){
        this("mike",12);
        System.out.println(this.name);
    }

    public T1(String name,int age){
        this.name = name;
        this.age = age;
        System.out.println("name,age");
    }
}
截屏2021-10-03 上午6.14.39.png

修饰符

  • public:公开

  • 受保护级别:protected修饰,对子类和包使用

  • 默认:没有修饰符

  • 私有:private

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5QM5mq6C-1647795839395)(/Users/zhaofei/Desktop/截图/截屏2021-10-03%20上午7.14.52.png)]

只有默认和public才可以修饰类

封装

封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作,才能对数据进行操作。

封装的好处

  • 隐藏实现细节

  • 可以对数据进行验证,保证安全合理

步骤:

1)将属性私有化

2)提供一个公共的set方法,用于对属性判断并赋值

3)提供一个公共的get方法,用于获取属性的值

继承

继承可以解决代码复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。

class 子类 extends 父类{

}

子类就会自动拥有父类定义的属性和方法
父又叫超类,基类
子类又叫派生类

子类继承了所有的属性和方法,非私有的属性和方法可以在子类中直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问

  • 子类必须调用父类的构造器,完成父类的初始化

  • 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不回通过

super只能在构造器的第一行和this()使用构造器一样。所以这两个不能共存

  • java所有类都是Object的子类
  • 子类最多只能继承一个父类(直接继承),java中是单继承机制。
  • 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

查找关系:

  • 如果子类有这个属性,并且可以访问,则返回信息

  • 接着父类,上级父类。

public class Details01 {
    public static void main(String[] args) {

        son son = new son();
        System.out.println(son.name);
    }
}

class Granda {
    String name = "granda";
    String hobby = "123";
    int age =33;
}

class father extends Granda {
    String name = "father";
    private int age = 99;
}

class son extends father {
    String name = "son";
}
截屏2021-10-04 上午6.49.47.png

super关键字

super代表父类的引用,用于访问父类的属性和方法和构造器等。

访问父类的属性,但不能访问父类的private属性

访问父类的方法,但不能访问父类的private方法

  • 调用父类的构造器(分工明确)

  • 当子类中和父类有重名时,为了访问父类,必须通过super,没有重名时 时一样的效果

  • super的访问不限于直接父类,如果爷爷类和本类中有同名成员,也可以使用,按就近原则

public class A {
    public int n1 = 888;
}

class B extends A{
    public int n1 = 100;
    public void test(){
        System.out.println(this.n1);
        System.out.println(super.n1);
    }
}
public class test {
    public static void main(String[] args) {
        B b = new B();
        b.test();
    }
}

//100

//888 super直接查找了父类

重写

子类的方法名称和父类的某个方法的名称、返回类型、参数一样,那我们就说父类的这个方法覆盖了父类的方法。

子类的方法的参数,方法名称,要和父类方法的参数,方法名称完全一样

子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类

子类方法不能缩小父类方法的访问权限

截屏2021-10-04 上午9.06.35.png

多态

方法或对象具有多种形态。多态是建立在封装和继承之上的。

  • 一个对象的编译类型和运行类型可以不一致,父类的引用指向子类的对象

    • Animal animal = new Dog();[animal 编译类型是Animal,运行类型是Dog]
      animal = new Cat();【运行类型变成了Cat,编译类型仍然是Animal】
      
  • 编译类型在定义对象时,就确定了

  • 运行类型是可以改变的

  • 编译类型看定义=号左边,运行类型看=右边

多态的前提是:两个类是继承关系

向上转型

父类的引用指向了子类的对象

Animal animal = new Dog();

  • 可以调用父类的所有成员(遵守访问权限),但不可以调用子类特有的成员。

  • 方法最终运行效果还得看子类的具体实现

    Animal animal = new Dog();[animal 编译类型是Animal,运行类型是Dog]
    animal = new Cat();【运行类型变成了Cat,编译类型仍然是Animal】
    
    cat.eat();//animal中有eat(),Dog中也有,那么调用的是Dog中的,也就是子类
    
    public class test1 {
        public static void main(String[] args) {
        A b = new B();
        System.out.println(b.age);//输出的是10 因为属性没有重写,根据编译类型算
    
    }
    }
    
    class A{
    
        public int age = 10;
    
    }
    
    class B extends A{
    
        public int age = 20;
    

    }

向下转型

语法:子类 引用名 = (子类类型)父类引用;

只能强转父类的引用,不能强转父类的对象

要求父类的引用必须指向的是当前目标类型的对象

当向下转型后,可以调用子类的所有成员

public class test1 {
  public static void main(String[] args) {
      A b = new B(); //b是父类引用

      B c = (B) b;
      System.out.println(c.age); //20这时已经是B了
  }
}

class A{
  public int age = 10;
}

class B extends A{
  public int age = 20;
}

属性没有重写一说,属性根据编译类型来算

instanceOf比较操作

动态绑定机制

java的动态绑定机制

  • 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定

  • 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。

class A{

public int i = 10;

public int sum(){

return getI()+10;

}

public int sum1(){

return i+10;

}

public int getI(){

return i;

}

}



class B extends A{

public int i =20;

public int sum(){

return i+20;

}

public int getI(){

return i;

}

public int sum1(){

return i+10;

}

}




A a = new B();

System.out.print(a.sum());//40 -> B.sum() i=20 20+20

System.out.print(a.sum1();//30->B.sum() i=20 i+10;

-------------------------------------------------------------------------

class B extends A{

public int i =20;

// public int sum(){

// return i+20;

// }

public int getI(){

return i;

}

//public int sum1(){

// return i+10;

// }

}

A a = new B();

System.out.print(a.sum());//B.sum()没有->A.sum() -> B.getI()->i=20;->20+10

System.out.print(a.sum1();// 20

多态数组

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

使用特有方法

Object类详解

enquals

==和equals的对比

==:比较运算符

  • 既可以判断基本类型,也可以判断引用类型

  • 如果判断基本类型,判断的值是否是相等的

  • 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象

equals方法

  • Object中的方法,只能判断引用类型

  • 默认判断的是地址是否相等,子类往往重写该方法,用于判断内容是否相等。比如Integer,String

public boolean equals(Object obj) {

        if (obj instanceof Integer) {

        return value == ((Integer)obj).intValue();

        }

    return false;

}
----------------------------------------------------------
//string
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

Hashcode

  • 提高具有哈希结构的容器的效率

  • 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的

  • 两个引用,如果指向的是不同对象,则哈希值是不一样的

  • 哈希值主要根据地址号来的,不能完全将哈希值等价于地址

  • 后面在集合,一般会重写

toString

默认返回:全类名+@+哈希值的十六进制,子类往往重写toString方法,用于返回对象的属性信息

重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString的形式

当直接输出一个对象时,toString会被默认调用

finalize

  • 当对象被回收时,系统调用该对象的finalize方法,子类可以重写该方法

  • 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁对象,在销毁该对象前,会先调用finalize方法

  • 垃圾回收机制的调用,是由系统来决定的,也可以通过System.gc()主动触发垃圾回收机制

package com.object_;
package com.object_;

public class finalize_ {
    public static void main(String[] args) {
        Car car = new Car("bwm");
        car = null;//指向此时断开,car就变成垃圾,垃圾回收器就会回收对象,在销毁对象前,会调用该对象的finalize方法
        //程序员就可以在finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接)
        //如果不重写,接回调用object的finalize
        System.gc();
        System.out.println("gogo");

    }
}

class Car{
    private String name;

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

    public void finalize() throws Throwable{

        System.out.println(this.name+"is running");

    }
}

//gogo
//bwmis running

断点调试

在断点调试过程中,是运行状态,是以对象的运行类型来执行的

调试看源码 force into

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值