Java基础:类与对象,递归,方法

类与对象的区别和联系

1.类是抽象的,概念的他是数据类型

2.对象是具体的实际的,代表一个具体事务

3.类是对象的模板,对象是类的个体

**对象在内存中的存在形式**

基本数据类型在堆,引用类型如String,数组在方法区

对象的属性

属性基本说明

1.成员变量or成员属性

属性的定义语法: public/protected/默认(包级私有/private

2.属性可以定义为任何类型

3.不赋值,就有默认值

如何访问属性

对象名.属性

如何创建对象

1.先声明后创建

Cat cat;

cat = new Cat();

2.直接创建

Cat cat = new Cat();

对象创建过程

1.栈:一般存放基本数据类型

2.堆:存放对象,数组等

3,方法区:常量池(比如字符串),类加载信息(只会加载一次)等

创建流程:

1.先加载Person类信息(属性和方法信息,只会加载一次)

2.在堆中分配空间,进行默认初始化,

3.把地址赋值给p,p就指向对象了

4.进行指定初始化

**类和对象的内存分配机制**

1.创建对象,加载类的信息,没赋值前是默认值

2.进行赋值,改变默认值

3.person p1 = p2;是一个拷贝传递,p1 p2共用同一个堆里的地址

成员方法

例:public void speak(){...}

public表示方法公开,void表示没返回值,speak是方法名,通过.调用方法

方法调用机制

1.当程序执行到int ret...时,会开辟一个独立的空间,然后会跳到方法所在的栈

2.方法运行完后通过返回值提前留存的地址返回到int res...=,

3.方法完成后会销毁方法

成员方法的好处

提高方法的复用性

可以将实现的细节封装起来,以便其他用户来调用

方法的定义

访问修饰符 返回值类型 方法名(参数表){//方法体

语句;

return 返回值;}

方法使用细节

方法修饰符(作用是控制方法使用范围),public,protected,默认,private

  1. 一个方法只能有一个返回值,若想要多个返回值,可以将其封装在数组中返回
public class Object01{
	public static void main(String[] args){
		AA a = new AA();
int[] res = a.getSumAndSub(1,4);
	}
}
class AA{
    public int[] getSumAndSub(int n1,int n2){
    int[] resArr = new int[2];
    resArr[0] = n1 + n2;    
    resArr[1] = n1 - n2;    
    return resArr;
}
  1. 返回类型可以为任何类型(基本/引用)
  2. 有无return 取决于是否是void ,且返回的数据必须一致或兼容(可以自动转换的)无return可以只写return;不能带返回值
  3. 一个方法可以有0个参数或者多个
  4. 参数类型可以为任何类型,调用时传入的参数必须一致或兼容
  5. 个数顺序都需一致,方法定义时的参数是形参,调用时的参数是实参
  6. 同一个类的方法可以直接调用,跨类调用 对象名.方法名
  7. 跨类的方法调用和方法的修饰符有关
  8. 在Java中,方法(包括普通方法和静态方法)不能单独写在类(class)的外面

**Java 方法传参机制**

基本数据类型传参

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

public class Object01{
	public static void main(String[] args){
		int a = 10;
        int b = 20;
        AA obj = new AA();
        obj.swap(a,b);//运行swap方法后,原来的ab值并不会发生了交换,
        //是因为运用到方法时会单独开一个栈,进行运算,无法影响到主栈
        System.out.println("a=" + a + "b=" + b);//10,20
	}
}
class AA{
    public void swap(int a,int b){
        System.out.println("交换前:" + "a=" + a + "b=" + b);//10,20
        int temp = a;
        a = b;
        b = temp;
        System.out.println("交换后:" + "a=" + a + "b=" + b);//20,10
    }
}

引用数据类型传参

引用数据类型传递的是地址(传递也是值,但值是地址),可以通过形参影响实参(包括对象和数组!)

public class Object01{
	public static void main(String[] args){
        AA obj = new AA();
        int[] arr = {1,2,3};
        obj.swap(arr);
        System.out.println("main方法的arr");
        for(int i= 0 ;i < arr.length;i++){
            System.out.print(arr[i] + "\t");// 200 2 3
//数组的值会改变是因为数组是引用数据类型,运行方法开辟新栈的时候传递过去的是数组的地址,
//arr栈和main栈里面的arr数组共用同一个地址相当于有两个变量保存了地址,改变地址所指向的值,也会影响主栈
//把其中一个地址置空不会影响另一个地址(地址是基本数据类型,改变其中一个地址的值不会影响的另一个地址
//故在方法里面改变数组的形参时也会影响到实参
        }
        System.out.println();
	}
}
class AA{
    public void swap(int[] arr){
        System.out.println("方法的arr");
        arr[0] = 200;//修改arr[0]
        for(int i= 0 ;i < arr.length;i++){
            System.out.print(arr[i] + "\t");//200 2 3
        }
        System.out.println();
    }
}

总结:

  • 基本数据类型的传递是值传递,传递的是值的副本。
  • 引用数据类型的传递在表面上看起来像是引用传递(因为它传递的是对象的引用),但实际上仍然是值传递(传递的是引用值的副本)。这个副本和原始引用都指向同一个对象,因此可以通过引用修改对象的状态,但无法通过引用本身改变它指向的对象(即不能改变引用的“地址”)

克隆对象

public class Object01{
	public static void main(String[] args){
        Person p1 = new Person();
        p1.age = 22;
        p1.name = "小罗";
        MyTools tools = new MyTools();//创建tools对象
        Person p2 =tools.copyPerson(p1);//
        System.out.println("p1的名字" + p1.name + "p1的年龄" + p1.age);
        System.out.println("p2的名字" + p2.name + "p2的年龄" + p2.age);
        //可以通过输出对象的hashCode来看看对象属性是否相同
	}
}
class Person{
    int age;
    String name;
}
class MyTools{
    public Person copyPerson(Person p){
    Person a = new Person();
    a.name = p.name;
    a.age = p.age;
    return a;
}
}

递归

简介:

Java中的递归是一种强大的编程技术,它允许一个方法直接或间接地调用自身。递归在解决可以分解为相似子问题的问题时特别有用,如遍历树或图结构、计算阶乘、求解斐波那契数列等。

简单递归演示


public class Recursion01{
	
	//编写一个main方法
	public static void main(String[] args){

		T t1 = new T();
		t1.text(4);
		int res = t1.factorial(5);
		System.out.println("5的阶乘res=" + res);
	}
}

class T{
	//递归初探
	public void text(int n){
		if(n > 2){
			text(n - 1);
		}
			System.out.println("n=" + n);
	}
	//阶乘
	public int factorial(int n){
		if(n == 1)
			return 1;
		else 
			return factorial(n - 1) * n;
	}
}

递归重要规则

  1. 执行一个方法时,就创建一个新的受保护的空间(栈空间)
  2. 方法中的局部变量是独立的,不会相互影响
  3. 如果方法中使用的是引用类型变量,就会共享该引用类型的数据
  4. 递归必须向退出递归的条件逼近,否则就是无限递归,出现死龟(SrackOverfloeError)
  5. 当一个方法执行完毕或者遇到return,就会返回,遵守谁调用就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕.

递归--斐波那契数列


public class Recursion01{
	
	//编写一个main方法
	public static void main(String[] args){

		//求斐波那契数列1,1,2,3,5,8,13...
		T t1 = new T();
		int res = t1.nub(-1);
		System.out.println("res=" + res);
	}
}

class T{
	//递归--斐波那契数列
		public int nub(int n){
			if(n >= 1){
				if(n == 1 || n == 2)
				return 1;
			else 
				return (nub(n-1)+nub(n-2));
		}else {
			System.out.println("请输入一个大于等于一的整数");
			return 0;
		}
	}
}

递归--猴子吃桃

//
public class Recursion02{

	//编写一个main方法
	public static void main(String[] args){
		A a = new A();
		int peach = a.eattz(-1);
		if(peach != -1)
			System.out.println("第一天桃子数为=" + peach);
	}
}
//day10 = 1;
//day9 = (day10 + 1)*2
//dayn = (day(n+1) + 1)*2
//如果输入的为n,dayn = eattz(n),day(n+1) = eattz(n+1)
//故两者关系应该表述为 eattz(n) = (eattz(n + 1) + 1)*2
class A
{
	public int eattz(int day)
	{
		//返回第n天有几个桃子
		if(day == 10)
			return 1;
		else if(day >=1 && day <= 9)
			return (eattz(day + 1) + 1)*2;
		else 
			return -1;
	}
}

递归--迷宫问题


public class MG{

	//编写一个main方法
	public static void main(String[] args)
	{
		/*思路分析
		1.使用一个二维数组来制定迷宫
		2.观察迷宫,指定规则,由于编译器可以默认初始化为0,
		我们可以把走不通的路设为1,能走的路设为0,这样可以简化初始化步骤
		3.观察可知
		*/
		int[][] map = new int[8][7];//二维数组表示迷宫
		for(int i = 0;i < 7;i++){//将第一行和最后一行置为1
			map[0][i] = 1;
			map[7][i] = 1;
		}
		for(int i = 0;i < 8;i++){//将第一列和最后一列置为1
			map[i][0] = 1;
			map[i][6] = 1;
		}
		//无规律的置1
		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();
		}
		T t1 = new T();
		t1.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 T{
	//使用递归回溯的思想来解决老鼠出迷宫
	//1.findway方法时专门来找出出迷宫的路径
	//2.如果找到返回true,否则返回false
	//3.map是二维数组,即表示迷宫
	//4.i,j就是老鼠的位置,初始化位置为(1,1)
	//5.由于是递归找路,所以规定 map数组的各个值的含义
	//0表示可以走 1表示障碍物 2表示可以走 3表示走过但是走不通
	//6.当map[6][5] = 2就表示找到通路了,可以结束了,否则就继续找
	//7.先确定老鼠找路的策略,下->右->上->左
	//改变走路策略也能走到终点
	public boolean findway(int[][] map,int i,int j){//接受下一个位置的位置
		if(map[6][5] == 2){
			return true;
		}else{
			if(map[i][j] == 0){//表示此处在的位置,为0表示可以进行下一步
				map[i][j] = 2;//假定该位置能走向下一个位置
				//走路策略 下右上左
				if(findway(map,i + 1,j)){
//先假定向下走,如果条件为真则进入下一层递归,
//对下下次路进行判断是否能走,可以再进行下下下次,不能则返回false,向下走的if为false,执行下一个if else重新进行相同判断,
//如果所有路都为false则把该点置为3,表示死路了,否则会一路找到终点,即map[6][5] == 2时,开始一路返回true,直至退出所有递归
					return false;
				}else if(findway(map,i,j + 1)){//向右
					return false;
				}else if(findway(map,i - 1,j)){//向上
					return false;
				}else if(findway(map,i,j - 1)){//向左
					return false;
				}else {
					map[i][j] = 3;
					return false;//都走不通,标记死机
				}
			}else{//为1,2,3走不了返回假
				return false;
			}
		}
	}
}
//回溯现象
//当一个位置置为3时,会返回上一个位置
//这是因为处在3这个位置会返回false,让上一次的向下为false,让他执行另一个else if
//不同路径都能找到终点,那如何求出最短路径呢?
//1.穷举2.图

递归问题--汉诺塔


public class Tower{

	//编写一个main方法
	public static void main(String[] args){
		T t = new T();
		t.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)
			//(1)移动上面所有盘到b,借助c
			move(num - 1, a , c , b);
			//(2)把最下面的这个盘移动到c
			System.out.println(a + "->" + c);
			//(3)再把b的所有盘移动到c,借助a
			move(num - 1, b,c,a);
		}
	}
}

递归--八皇后问题

方法重载

Java允许在同一个类中有多种同名方法的存在,但要求形参不一样

注意细节:

1.方法名相同,

2.形参类型或个数或顺序至少有一种不同

3.返回类型无要求

可变参数

Java允许将同一个类中多个同名同功能但参数不同的方法,封装成一个方法,就可以通过可变参数实现

1.int...nums表示的是可变参数,类型是int,即可接受多个参数int(0-多)

2.可变参数实参可以为数组(由数组等效表示多个实参)

3.可变参数本质就是数组,即可以.length,遍历求和等

4.可变参数可以和普通参数放在同一个列表,但可变参数必须放在后面

5.一个形参列表中只能出现一个可变参数


public class VarParameter01{

	//编写一个main方法
	public static void main(String[] args){
		T t = new T();
		int[] arr = {1,2,3};
		System.out.println(t.sum(1,5,7,9));
		System.out.println(t.sum(1,5));
		System.out.println(t.sum(arr));
	}
}
class T{
	//可以计算2,3,4,...多个数的和
	//1.int...nums表示的是可变参数,类型是int,即可接受多个参数int(0-多)
	//2.使用可变参数时可以当做数组来使用,即可以.length,遍历求和等
	public int sum(int... nums){
		//4.可变参数可以和普通参数放在同一个列表,但可变参数必须放在后面
		//(int... nums,double a)x
		//(double a,int... nums)对
		System.out.println("接受的参数个数是=" + nums.length);
		//遍历求和
		int res = 0;
		for(int i = 0;i < nums.length;i++){
			res += nums[i];
		}
		return res;
	}
}
/*
public class VarParameter01{

	//编写一个main方法
	public static void main(String[] args){
		T t = new T();
		System.out.println(t.sum("刘宇", 13.2, 11.8));  
        System.out.println(t.sum("小罗", 12.0, 12.0, 12.0));  
        System.out.println(t.sum("好友位", 2.0, 8.0, 8.0, 8.0, 5.0, 4.0)); 
	}
}
class T{
	public String sum(String name,double... nums){
		double res = 0;
		for(int i = 0; i < nums.length;i++){
			res += nums[i];
		}
		return name + nums.length + "们课的成绩总分为=" + res;
	}
}*/

变量作用域

1.全局变量:也就是属性,作用域为整个类体;可以被本类使用或者其他类使用,通过对象调用

2.局部变量:除了属性之外的局部变量,只能在它定义的地方使用.

3.全局变量可以不赋值直接使用,因为有默认值,但局部变量不能,因为局部变量没有默认值

4.属性和局部变量可以重名,访问时遵循就近原则

5.同一个作用域定义局部变量不能重名

6.属性生命周期长,伴随着对象的创建而创建,伴随对象的销毁而销毁.局部变量生命周期短,伴随代码块的执行而创建,伴随代码块的销毁而销毁.

7.属性前面可以加修饰符但局部变量不行

构造方法/构造器(即构造函数)

构造器细节即注意事项

1.构造器的修饰符可以默认

2.构造器没有返回值

3.方法名和类名一样

4.参数列表和成员方法一样的规则

5.构造器的调用由计算机本身调用,完成对对象的初始化不是创建对象

修饰符 类名(形参){...}

6.构造器可重载,没定义会有默认的构造器,若定义了构造器则默认的会被覆盖


public class VarScope{

	//编写一个main方法
	public static void main(String[] args){
		Person p = new Person();
		System.out.println("p的信息 name="+ p.name + "age=" + p.age);
		Person p1 = new Person("小罗",19);
		System.out.println("p1的信息 name="+ p1.name + "age=" + p1.age);
	}
}
class Person{
	int age;
	String name;
	public Person(){
		age = 18;
	}
	public Person(String pname,int Age){
		name = pname;
		age = Age;
	}
}

对象创建的流程分析

真正的对象在堆里,栈里的对象实际上是一个地址指向堆里(就像名字和人一样)

注意:构造器初始化会覆盖显式初始化

this关键字

什么是this

java虚拟机会给每个对象分配this,代表当前对象

this的理解

this使用细节和注意事项

1.哪个调用this,this就指向谁

2.this可以用来访问本类的属性,方法,构造器

3.访问方法:this.方法名(参数列表)

4.访问构造器:this(参数列表);注意只能在构造器调用另一个构造器,如果要在构造器使用this,必须将this置于第一条语句

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


public class This01{

	//编写一个main方法
	public static void main(String[] args){
		//T t1 = new T("小罗",19);
		T t1 = new T();
		//t1.f2();
		t1.f1();
	}
}
class T{
	String name = "刘宇";
	int age = 18;
	public T(){
		//通过this访问另一个构造器
		this("yingran",80);
		System.out.println("T()构造器");
	}
	public T(String name,int age){
		/*this.表示当前对象的属性
		//name = name;
		this.name = name;
		//age = age;
		this.age = age;*/
		System.out.println("public T(String name,int age)构造器被调用");

	}
	//由于构造器的就近原则,默认为形参
	public void f1(){
		String name = "有味";
		int age = 9;
		System.out.println("name= " + name + "age=" + age);//就近原则
		System.out.println("name= " + this.name + "age=" + this.age);//准确访问属性
		//name= 有味age=9
		//name= 刘宇age=18
	}
	/*
	public void f2(){
		System.out.println("f2方法被调用");
		f1();
		this.f1();
	}*/
}
  • 13
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值