Java基础部分学习:04、面向对象

本文详细介绍了Java中的类与对象的概念,包括如何创建和初始化对象,以及对象内存布局的理解。讲解了属性的访问范围、默认值以及对象分配机制,强调了空指针异常的处理。此外,还阐述了方法的使用细节、参数列表、递归调用原理以及方法重载和可变参数的应用。同时,讨论了作用域规则,构造器的功能以及this关键字的用法,最后提到了对象创建的完整流程。
摘要由CSDN通过智能技术生成

1、类和对象:

类:抽象的、概念的一类事物,如人类。
对象:具体的、实际的具体事物。如小明这个人。


2、类和对象的创建:

public class CreateObject {
    public static void main(String[] args) {
        Cat cat1 = new Cat();
        cat1.name = "小花";
        cat1.age = 12;
        cat1.color = "白色";
        System.out.println(cat1.name + cat1.age + cat1.color);
    }
}

class Cat{
    String name;
    int age;
    String color;
}
//1、先声明再创建:
Cat cat;
cat = new Cat();

//2、直接创建:
Cat cat = new Cat();

3、对象内存布局:

1、栈:一般存放基本数据类型(局部变量)
2、堆:存放对象、数组等
3、方法区:存放常量池(常量、字符串),类加载信息

在这里插入图片描述

3.1、流程简单分析:

1、先加载类信息(方法区中:属性、方法信息),只会加载一次。
2、在堆中分配空间,进行默认初始化:如int=0;
3、将堆中地址赋值给栈中的对象名,该对象名就指向该对象。
4、进行指定初始化:比如:p.name=“jack”;


4、属性注意细节:

1、属性访问范围:public、protectted、默认、private。
2、属性的定义可以为基本数据类型或者引用类型。
3、属性如果不赋值,有默认值,和数组规则一样:int/short/byte/long:0;
float/double:0.0;char:\u0000;Boolean:false;String:null


5、对象分配机制:

Person p1 = new Person();
p1.age = 10;
p1.name = "李四";
Person p2 = p1;
System.out.println(p2.age);

在这里插入图片描述


6、空指针异常:NullPointException

当对象地址为空时,再去访问就会出现空指针异常

Person p = new Person();
p.age = 10;
p.name = "李四";
p=null;
System.out.println(p.age);  // 报错 NullPointException

7、对象方法:

public class Person {
	String name;
	int age;
	String sex;
	/*
	1、public:表示是一个公开方法。
	2、void:表示该方法没有返回值。
	3、dance():dance是方法名;():形参列表
	*/
	public void dance() {
		System.out.println("我会唱歌");
	}
}

方法的调用:

Person p = new Person();
p.dance();

8、方法的使用细节:

1、一个方法最多有一个返回值。如果要返回多个值,可以返回一个数组,将返回值放在数组里面。

2、返回类型可以为任意类型,包含基本类型和引用类型(数组、对象)。

3、如果方法要求有返回类型,则方法体最后执行的语句必须为return值。

4、void方法可以不用return语句,或者只写return。

5、使用驼峰命名法,如getSum。


9、参数列表:

1、一个方法可以没有或者有任意多个参数。

2、参数类型可以为任意类型,包含基本类型或者引用类型。

3、形参、实参类型及个数要一致。


10、方法调用细节:

1、同一个类的方法可以直接调用,不用创建对象来调用。

2、跨类方法要创建对象,使用对象名来调用。


11、方法传参机制:

1、对于基本数据类型,传递的是值(值拷贝),形参的任何改变不会影响实参。
在这里插入图片描述
调用方法的会会在栈中再开辟一个方法空间,他和main方法是两个不同的空间,因此方法空间里面发生的形参改变不会影响到实参。

2、对于引用数据类型:传递的是地址值,两个指向同一个空间,因此,形参发生改变也会影响到实参。
在这里插入图片描述


11、练习:

1、克隆对象:

public class CreateObject {
    public static void main(String[] args) {
        Person  p1 = new Person();
        p1.name = "lisa";
        p1.age = 10;
        MyTools myTools = new MyTools();
        Person p2 =myTools.copyPerson(p1);
    }
}

class Person {
    String name;
    int age;
}

class MyTools {
    /*1、 Person:该方法返回类型为Person对象类型,
       返回类型不可以随意写,必须是以及存在的类。
      2、(Person p):形参为Person对象,对象名为ps
      就和形参类型为 int,形参名为 num一样,其实形参里面起什么名都可以,
      他只是一个形参,只是接收形参的。
      3、新建一个person对象,对象名为p2
      4、将形参对象person的姓名、年龄赋值给p2
     */
    public Person copyPerson(Person ps) {
        Person p2 = new Person();
        p2.name = ps.name;
        p2.age = ps.age;
        return p2;
    }
    
}

11、方法递归:

1、即方法自己调用自己。

在这里插入图片描述
方法递归输出结果是从后往前输出的。即没调用一个方法会开辟一个栈,由最后一个栈往前输出。 当输出到main栈时,如果后面没有代码就结束执行,main方法后面还有代码则继续执行。

2、递归阶层:

int res = factorial(5);
System.out.println(res);  // 120
public int factorial(int n) {
	if(n == 1) {
		return 1;
	} else {
		return factorial(n -1) * n;
	}
}

在这里插入图片描述


3、递归调用机制:

1、每次执行一个方法时,就创建一个新的受保护的独立空间(栈空间),每个栈空间里面的变量都是独立的,不会互相影响。

2、如果方法中使用的是引用类型的变量(如数组、对象),就会共享该引用数据类型的数据。

3、递归必须向退出递归的条件逼近,否则就是无线递归,出现:StackOverflowError。

4、当一个方法执行完毕,或者遇到了return,就会返回,遵守谁调用这个方法就把结果返回给谁(从上往下一级一级返回结果,一直到最前面)。


11、递归练习题:

1、猴子吃桃问题:猴子每天吃一半桃子+1个,到了第10天,发现只剩1个桃子了。
规则:前一天的桃子 = (后一天桃子 + 1) * 2 ; 后一天:day + 1

public int Peach(int day) {
	if(day == 10) {
		return 1;
	} else if (day >= 1 && day <= 9) {
		retuen (peach(day + 1) + 1) * 2;
	}
}

2、走迷宫:

public class MiGong {
    public static void main(String[] args) {
        int map[][] = new int[8][7];
        for (int i = 0; i < map.length; i++) {
           for (int j = 0; j < map[i].length; j++) {
               map[0][j] = 1;
               map[7][j] = 1;
               map[i][0] = 1;
               map[i][6] = 1;
               map[3][1] = 1;
               map[3][2] = 1;
           }
        }
        
        Find find = new Find();
        find.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 Find {
    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;   // 将可以走通的路数字设置为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;  // 3:表示死路,四边都走不通
                    return false;
                }
            } else {
                return false;
            }
        }
    }
}

在这里插入图片描述


12、方法重载:方法名一致,形参列表不同即可。

基本介绍:

Java中允许在一个类中,多个同名方法的存在,到要求形参列表不一致。

注意事项:
1、方法名:必须一致。

2、形参列表:必须不同(形参类型或个数或顺序至少有一样不同,参数名无要求:int n 和 int a 是一样的)。

3、返回类型:无要求。

重载的意义:

1、减轻了起名的麻烦。

2、减轻了记名的麻烦。

public class Overload {
  public static void main(String[] args) {
    Methods methods = new Methods();
    int cal1 = methods.cal(12);
    int cal2 = methods.cal(12,22);
    String cal3 = methods.cal("hello");
    System.out.println(cal1 + " " + cal2 + " " + cal3);
  }
}

class Methods{
  public int cal(int n) {
    return n * n;
  }

  public int cal(int n1, int n2) {
    return n1 * n2;
  }

  public String cal(String str) {
    return str;
  }
}

13、可变参数:…

定义:将方法名相同、功能相同但是参数列表不同的方法封装成一个方法

要求:求2个数、3个数、4个数的和
如果用重载来解决的话就需要定义多个不同的方法,但是这些方法功能都是一样的,唯一不同的就是参数列表。

// int...  就是参数个数可以为(0~多个)
// sums:参数名
// 可以将可变参数当做数组,他也有大小
public int sum(int... sums) {
	int res = 0;
	for(int i = 0; i < sums.length; i++) {
		res += sums[i];
	}
	return res;
}

使用细节:

1、可变参数的实参可以是0或者任意多个。

2、可变参数的实参可以为数组,可变参数的本质就是数组。

public class Overload {
  public static void main(String[] args) {
    Methods methods = new Methods();
    int[] arr = {1, 2, 3};
    int sum = methods.sum(arr);
    System.out.println(sum);
  }
}
class Methods{
  public int sum(int... nums) {
    int res = 0;
    for (int i = 0; i < nums.length; i++) {
      res+=nums[i];
    }
    return res;
  }
}

3、可变参数可以和普通类型参数一起放在形参列表,但必须保证可变参数在最后。

  public int sum(int n1, int n2 ,int... nums) {
    int res = 0;
    for (int i = 0; i < nums.length; i++) {
      res+=nums[i];
    }
    return res;
  }

14、作用域:

总结:作用域就是离自己最近的外层大括号范围就是变量的作用域

1、在Java中,主要的变量就是属性(成员变量)和局部变量。

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

3、Java作用域分类:

全局变量:作用域为整个类,该类中的方法可以使用。

局部变量:作用域为定义它的代码块中。

4、
全局变量可以不赋值,直接使用,因为有默认值。

局部变量必须赋值后,才能使用,因为没有默认值。

class Methods{
  int num;
  String name = "Mary";

  public void find() {
    int age;
    String address = "china";
    System.out.println(num);
    System.out.println(name);

   // System.out.println(age);  // 报错,局部变量未赋值不可直接使用
  }

作用域注意事项:

a、属性(成员变量)和局部变量可以重名,访问时遵循就近原则。

class Methods{
  String name = "Mary";
  public void find() {
    String name = "King";
    System.out.println(name);  // king
  }
}

b、在同一个作用域中,两个局部变量不可重名。

c、属性生命周期较长,伴随着对象的创建而创建,随着对象的死亡而死亡。

局部变量,生命周期较短,伴随着代码块的执行而创建,伴随着代码块的结束而死亡。

6、区别:

全局变量(属性):可以在本类使用,也可以在其它类使用(通过对象调用)。

局部变量:只能在本类的方法中使用。

修饰符不同:全局可以加修饰符,局部不可以加。


15、构造器/构造方法

它是类的一种特殊方法,主要作用是完成对新对象的初始化。
以前我们给对象赋值的时候都是在对象创建完成之后赋值:对象名.属性名来赋值,如:p.name = lisa;
有了构造方法之后,就可以在创建对象的同时给对象赋值。

public class Construction {
    public static void main(String[] args) {
        Persons persons1 = new Persons("lisa", 12);
        Persons persons2 = new Persons("lisa");
    }
}

class Persons {
    String name;
    int age;
    public Persons(String pName, int pAge) {
        name = pName;
        age = pAge;
    }
    public Persons(String pName) {  // 构造器重载
        name = pName;
     
    }
}

1、特点:
1、方法名必须和类名一致。

2、没有返回值。

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

2、使用细节:

1、一个类可以定义多个不同构造器,及构造器的重载(构造器本质是一个方法,方法就可以重载)。

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

3、在创建对象时,系统自动调用该类的构造器,不能自己去调用:如:方法名.构造器名。

4、如果没有写构造器,那么程序会默认生成一个无参构造器。因此我们创建对象时都是这样创建的:

Dog dog = new Dog();   // 小括号里面是空的
claa Dog {
/*
	dog() {}  // 默认生成
*/
}

5、如果我们自己定义了一个构造器,那么原来的无参构造器就被覆盖了,不能再使用了(创建对象时必须初始化)。如果还想使用无参构造器,那么必须显性的定义一下。

// 利用无参构造器,设置所有人的性别都是男:
dog() {
	sex = "男";
]

在这里插入图片描述
对象创建流程分析:

1、首先在方法区中加载类信息,只会加载一次。
2、在堆中分配空间(地址)。
3、完成对象初始化(构造器)【1、首先默认初始化 int=>0;String=> null。 2、显性初始化age=90;name=null。3、构造器初始化:age=20;name=小倩】
4、将对象在堆中的地址返回给p(p是对象名/对象的引用)。


16、this:

Java虚拟机会给每个对象都分配this,因此this指向的就是该对象自己。
哪个对象调用,this就指向哪个对象。
在这里插入图片描述
使用this升级构造器:

class Persons {
    String name;
    int age;
    public Persons(String name, int age) {
    /*下面是错误写法:忽略了变量作用域原则。
		name = name;   这个两个name都是构造器里面的name,左边那个不是上面的全局name
		age = age;
	*/
        this.name = name;   // this.name:就是这个对象的name,那么就是上面的全局name了
        this.age = age;
    }
    public Persons(String pName) {  // 构造器重载
        name = pName;
     
    }
}

this使用细节:

1、this关键字可以用来访问本类的属性(使用this的话访问的是全局变量)、方法、构造器。

2、this可以用来在构造器中访问另一个构造器,必须写在第一条语句。this(参数列表);

public Cat() {
	this("lisa", 100);
}

public Cat(String name, int age) {

}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值