面向对象编程(初级)

类和对象

类是一种数据类型
对象是具体的,实际的,代表一个具体的事物
类是对象的模板,对象是类的一个个体,对应一个实例

import java.util.Scanner;
public class Array05{
	public static void main(String[] args){
		//单独变量定义,麻烦
		String cat01 = "jeck";
		String cat02 = "mary";
		int cat01age = 4;
		int cat02age = 100;

		String cat01color = "white";
		String cat02color = "black";
		Scanner scanner = new Scanner(System.in);
		//数组 ===>数据类型无法体现
		String[] cat01 = {"jeck","3","white"};

		//使用oop面向对象来解决
		//实例化一只猫[创建一个猫对象]
		Cat cat01 = new Cat();
		cat01.name ="jeck";
		cat01.color = "white";
		cat01.age = 3;

        cat02.name ="mary";
		cat02.color = "black";
		cat02.age = 100;

		//使用
		System.out.println("第一只猫的名字"+ cat01.name + "颜色和年龄:"+ cat01.age +" " + cat01.color);
	}
}
//定义一个猫类Cat -> 自定义的数据类型

class Cat{
	//属性
	String name;
	int age;
	String color;

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

在这里插入图片描述

注意事项和细节

属性的定义语法同变量 示例:访问修饰符 属性类型 属性名;四种访问修饰符:public proctected 默认 private
属性的定义类型可以为任意类型,包括基本类型和引用类型
属性如果不赋值,默认值规则和数组一致

如何创建对象

1、Cat cat;
cat = new Cat();先声明再创建
2、直接创建
Cat cat = new Cat();

类和对象内存分配机制

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

java创建对象基本流程

Person p = new Person();
p.name = “jack”;
p.age = 10;
1、先加载person类信息
2、在堆中分配空间,进行默认初始化,把对象在堆内地址返回给p
3、把地址赋给p,p就指向对象
4、进行指定初始化

成员方法(方法)

1、当程序执行到方法时,就会开辟一个独立的空间(栈空间)
2、当方法执行完毕,或者执行到return语句时,就会返回
3、返回到调用方法的地方,继续执行后面的代码
4、当main方法执行后,整个程序退出,栈空间被销毁
具体方法调用实例

优点:提高代码复用性
可以将实现的细节封装起来,供其他用户调用

public class Method01{
	public static void main(String[] args){
		//方法使用
		//方法写好后如果不调用,不会生效
		//先创建对象,再调用方法
		Person p1 = new Person();
		p1.speak();//调用方法
		p1.cal01();
		p1.cal02(5);//调用cal02方法,把5传给n;
		//把getSum方法返回的值赋给变量returnRes;
		int returnRes = p1.getSum(5,10);//传入两个参数
		System.out.println(returnRes); 
	}
}

class Person {
	String name;
	int age;
	//方法
	//添加speak成员方法,输出我是一个好人
	//public 表示方法是公开的,void 表示方法没有返回值
	//speak是方法名()形参列表
	//{}方法体,写我们需要执行的代码
	public void speak(){
		System.out.println("我是一个好人");
	}

	public void cal01(){
		int res = 0;
		for(int i=1;i<=1000;i++){
			res+=i;
		}
		System.out.println(res);
	}
	//传入一个形参
	public void cal02(int n){
		int res = 0;
		for(int i=1;i<=n;i++){
			res+=i;
		}
		System.out.println(res);
	}

	//添加getSum方法,可以计算两个数的和
	//int 表示它一定会返回一个int值,可以接收两个形参(用户可以传入两个数)
	//return res;返回值res
	public int getSum(int num1,int num2) {
		int res = num2 + num1;
		return res;
	}
}
成员方法的使用:

public 返回数据类型 方法名(参数列表){方法体
语句
return 返回值;
其中参数列表表示输入的参数 返回数据类型表示方法的输出数据类型(void表示没有返回值),return表示返回的值,不一定要有return

返回数据类型的注意事项和使用细节

1、一个return只能返回一个返回值,多个结果可以返回数组。返回类型可以是任意类型;
2、如果方法要求有返回值,那么最后依据必须是return语句,返回值类型必须和方法定义的类型一致或者兼容,符合自动类型转换规则。
3、void 可以没有return,或者只有return(后面不能带具体的值)。

形参列表注意事项和使用细节

1、方法可以有0个参数或者多个参数,参数间用逗号隔开。
2、调用方法实际传进去的值叫实参,而方法中的两个数叫形参;两个参数类型,个数、顺序必须一致;
方法中不能再定义方法,方法不能嵌套定义。

方法调用细节

1、同一个类中的方法可以互相调用,直接调用,不需要创建对象;

class A{
    public void print(int n){
        System.out.println("print方法被调用" + n);}

    public void sayok(int n){
        print(10);
        System.out.println("print方法被调用" + n);}
    public void M1(){
        B b = new B();
        b.HI();
        System.out.println("m1方法被调用");}
 }
 class B{
    public void HI(){
        System.out.println("HI方法被调用");}
 }

2、跨类别方法调用:需要通过创建对象名调用
3、调用还与访问修饰符有关。

成员方法的传参机制(parameter)

基本数据类型传递的是值,形参的改变不影响实参

引用数据类型的传参机制

引用类型传递的是一个地址,可以通过形参影响实参
克隆一个对象,两个不是同一个对象但是有相同的属性

public class Method04{
	public static void main(String[] args){
		Person p1 = new Person();
		p1.age = 15;
		p1.name = "jack";
		Mytools tools = new Mytools();
		//引用方法需要新建一个类再从这个类中找方法,最后引用
		Person p2 = tools.copyPerson(p1);
		System.out.println(p1.name + p1.age);
		System.out.println(p2.name + p2.age);
		
	}
}

class Person{
	String name;
	int age;
	
}
class Mytools{
	//编写一个方法克隆对象
	public Person copyPerson(Person p) {
		Person p2 = new Person();
		p2.name = p.name;
		p2.age = p.age;

		return p2;
	}
}
方法的递归调用

在方法中调用方法,让程序更加的简洁;
递归的具体使用内存1、打印问题
在这里插入图片描述
从最底层开始输出,依次往外输出。
当执行一个方法时就会创建一个新的受保护的空间
方法的局部变量是独立的,不会互相影响
如果方法中使用的是引用类型变量,就会共享该引用类型的数据
递归必须想退出递归的条件逼近,不然就会死循环
当一个方法执行完毕时,或者遇到return就返回,遵守谁调用谁返回

通过递归实现小老鼠走迷宫和汉诺塔问题

具体的实现思路已经在代码中给出,但是递归最重要的就是找到退出条件,会分析栈中内存图。

public class MiGong{
	public static void main(String[] args){
		//小老鼠走迷宫问题
		//先创建迷宫,用二维数组表示 int[][] map = new int [8][7];
		//2、0表示可以走的路,1表示障碍物
		int[][] map = new int [8][7];
		//地图绘制,将最上下两行全部设置为1;
		for(int i=0;i<map.length;i++){
			for(int j = 0;j<map[i].length;j++){
				if( i==0 || i==7){
					map[i][j] = 1;
				}
				else if(j==0||j==6){
					map[i][j] = 1;
				}
			}
		}
		map[3][1] = 1;
		map[3][2] = 1;
		
		//使用findWay给老鼠找路
		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{
	//使用递归回溯思想来解决
	//专门找出迷宫的路径,如果找到返回ture,没有则返回false
	//map就是迷宫,i,j就是老鼠的位置
	//初始化位置为[1][1]
	//规定推出条件map数组的各个值的含义
	//0表示可以走的路,1表示障碍物2表示可以走3表示走过但是走不通
	//当map[6][5] = 2时,找到通路,退出,否则继续找路
	//先确定老鼠找路的策略,下面走不通走右边-》上-》左
	//策略也可以改变,路径很可能不一样
	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;
			}
		}
	}
}
//汉诺塔移动的步骤输出
public class HanoiTower{
	public static void main(String[] args){
		Tower t1 = new Tower();
		t1.move(2,'A','B','C');
	}
}
class Tower{
	//a,b,c表示3根柱子num表示盘子数
	public void move(int num,char a ,char b, char c){
		if(num ==1){
			System.out.println(a+"->" + c);
		}else {
			//所有的盘子都看出只有两个盘,分最下面一个和上面的
			//首先把a塔上面的那个盘移动到b塔,可以借助c塔
			move(num-1,a,c,b);//把a移动到b后剩下的就是a->c,所以输出a->c
			//最下面的盘移动到c
			System.out.println(a+ "->" + c);//a当前剩下的盘子移动到c
			//再把b柱子上的所有盘移动到c,借助a塔
			move(num-1,b,a,c);
		}
	}
}

方法重载机制

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

使用注意事项

1、方法名称必须一样
2、形参的类型或个数或者顺序必须有一个不一样,参数名称没有要求
3、返回类型没有要求

可变参数

1、Java允许将同一个类中多个同名同功能但是参数个数不同的方法,封装成一个方法,可以通过可变参数实现
2、基本语法: 访问修饰符 返回类型 方法名(数据类型…形参名){}
可变参数的实参可以是数组
可变参数可以和普通参数方法一个参数列表,但是必须保证可变参数在最后。
一个形参列表只允许有一个可变参数

class M{
//使用可变参数时,可以把输入的同类型数据当作数组使用
//int...表示输入任意个int类型的数据。
public int sum(int... nums){
System.out.println("接收的参数个数为" + nums.length)int res = 0;
for(int i=0;i<nums.length;i++){
res +=nums[i];
}
}
}

public class VarParameter01{
	public static void main(String[] args){
		S m = new S();
		String grade = m.Sum("jack",56,78);
		System.out.println(grade);
	}
}
class S{
	public String Sum(String name, int...nums){
		int res = 0;
		//String[]  grade = new String[2];
		for(int i=0;i<nums.length;i++){
			res += nums[i];
		}
		return name + "成绩总分为" + res;
	} 
}

作用域

在Java中,主要的变量就是属性(成员变量)和局部变量(在成员方法中定义的变量)
作用域分类:全局变量,作用域为整个类体;而局部变量就是除了属性之外的其他变量,作用域为定义它的代码块中,全局变量可以不赋值,直接使用,而局部变量必须赋值后才能使用,因为没有默认值。
注意事项
*属性和局部变量可以重名,访问时遵循就近原则。
*同一个作用域中,两个局部变量不可以同名
*属性生命周期较长,随着对象的创建和死亡,而局部变量则是随着代码块的创建和死亡,只是一次方法的调用过程。
*全局变量(属性):可以在本类中使用,也可以通过创建对象被其他类调用,形参也可以传入对象
*局部变量:只能被自己的类调用
*修饰符:全局变量(属性)可以加修饰符;局部变量不可以加修饰符

构造器/构造方法(constructor)

基本语法:[修饰符] 方法名(形参列表){
方法体;}
主要作用:完成对新对象的初始化,不创建对象,在创建对象时,系统自动调用构造器。
1、构造器的修饰符可以默认,也可以其他;
2、构造器没有返回值
3、方法名和类名字必须一样
4、参数列表和成员方法一样规则
5、构造器的调用,由系统完成
6、构造器也叫构造方法,也可以进行方法的重载
7、如果没有写构造器,系统会自动生成一个默认无参构造器(类名(){})
javap反编译,把class转成代码。
8、一旦自定义了构造器,默认无参构造器被覆盖,无法使用,除非重新定义一个无参构造器。

public class Constructor01{
	public static void main(String[] args){
		Person p1 = new Person("smith",98);//new后,系统会自动调用构造器
		Person p2 = new Person();
	}
}

class Person{
	String name;
	int age=90;
	//完成对象属性的初始化
	public Person(String pName,int pAge){
		name = pName;
		age = pAge;
	}
	public Person(){
		age = 18;
	}
}

流程分析:1、加载Person类信息,只加载一次
2、在堆中分配地址
3、完成对象初始化(首先默认初始化age = 0,name =null,显式初始化,age
=90,name=null,构造器初始化 age = 20,name=null。)
4、把对象在堆中的地址返回给p1或者p2。
当属性名和构造器形参名称一样时,会遵循就近原则,其中的name和age只是局部变量而不是属性,无法给属性赋值。这个问题可以通过this关键字来解决。

this关键字

this.name this.age当前对象的属性,不再时局部变量的age和name(this代表当前对象)
hashCode:返回对象的哈希码值,就是把他的地址转换成整数输出
在这里插入图片描述
this 关键字可以用来访问本对象的属性、方法和构造器;
this用于区分当前类的属性和局部变量
访问成员方法的语法:this.方法名(参数列表);
访问构造器语法this(参数列表):注意只能在构造器中使用;(只能在构造器中区调用另一个构造器)
this不能再类定义的外部使用,只能在类定义的方法中使用。

public class Constructor01{
	public static void main(String[] args){
		Person p1 = new Person("smith",98);//new后,系统会自动调用构造器
		Person p2 = new Person();
		p1.f1();
	}
}

class Person{
	String name;
	int age;
	//完成对象属性的初始化
	//在一个构造器中访问另一个构造器
	public Person(){
		this("jack",26);//访问下面的构造器,如果有this的语法,必须放在第一条语句。
	}
	public Person(String pName,int pAge){
		name = pName;
		age = pAge;
	}
	//想要将构造器中的名字简洁,使用this关键字。
	public Person(String name ,int age){
		this.age = age;
		this.name =name;//age和name都是当前对象的属性
	}
	public void f1(){
		//调用本类的方法
		f1();
		this.f1();
	}
}

具体练习题
通过构造器来求圆的面积

public class Homework07{
	public static void main(String[] args){
		//通过定义两个类求出不同半径的圆面积
		Circle c = new Circle();
		PassObject p= new PassObject();
		p.printAreas(c,5);
	}
}
class Circle{
	double radius;
	public Circle(){

	}
	public Circle(double radius){
		this.radius = radius;
	}
	public double findArea(){
		return Math.PI*this.radius*this.radius;
	}
	//添加一个方法setRadius,修改对象半径值
	public void setRadius(double radius){
		this.radius = radius;
	}
}
class PassObject{
	public void printAreas(Circle c, int times){
		System.out.println("Radius" + "\t" + "Area");
		for(int i=1;i<=times;i++){
			c.setRadius(i);
			System.out.println(i + "\t" + c.findArea());
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值