学习内容
一、类与对象
1.快速入门
类:它是一个抽象的,概念的,代表一类事物,比如人类,猫类…, 即它是数据类型
对象:对象是具体的,实际的,代表一个具体事物, 即 是实例
类和对象的关系:类是对象的模板,对象是类的一个个体,对应一个实例
public class test{
public static void main(String[] args) {
new Penson(); //创建了一个人对象
Penson Penson1 = new Penson(); //把人的对象赋值给Penson1,Penson1就是一个对象
//对Penson1对象中的属性进行赋值
Penson1.name = "张三";
Penson1.age = 20;
Penson Penson2 = new Penson(); //再创建一个人的对象叫Penson2
//对Penson2对象中的属性进行赋值
Penson2.name = "李四";
Penson2.age = 21;
//对象属性的访问
System.out.println("Penson1的属性为:"+ Penson1.name +" "+ Penson1.age);
System.out.println("Penson2的属性为:"+ Penson2.name +" "+ Penson2.age);
}
}
//定义一个人类,其中Penson就是自定义数据类型
class Penson{
String name; //姓名
int age; //年龄
}
2.属性/成员变量
属性/成员变量:成员变量就是属性,它是类的一个组成部分,一般基本数据类型,或者是引用数据类型(对象、数组等)如:上面定义狗类的 int age 就是属性;
说明:如果属性不赋值则由默认值 比如int的默认值为0
定义格式:访问修饰符 属性类型 属性名;
访问修饰符:就是控制属性的访问范围,一共分为四种分别为 public、proctected、default(默认)、private。
访问权限表:
修饰符 | 同一个类 | 同一个包内的类 | 不同包内的子类 | 其他包 |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
proctected | 可以 | 可以 | 可以 | 不可以 |
default | 可以 | 可以 | 不可以 | 不可以 |
private | 可以 | 不可以 | 不可以 | 不可以 |
3.Java内存结构的分析
JVM内存主要分为三个部分:
- 栈:一般存放基本数据类型和局部变量
- 堆:存放对象、数组等
- 方法区:常量池(常量,比如字符串等)、加载类的信息 如:类的属性、方法等
二、成员方法
1.基本介绍
在某些情况下,我们要需要定义成员方法(简称方法)。比如上面那个人类:除了有一些属性外( 年龄,姓名…),人类还有一 些行为比如:说、计算、睡觉等。这时就要用成员方法才能完成。现在要求对 Person 类完善。
2.定义格式
访问修饰符 返回数据类型 方法名(形参列表…) {
//方法体 语句;
return 返回值;
}
- 访问修饰符:public、proctected、default(默认)、private
- 返回值类型:void表示没有返回值,int表示返回整形
- 形参列表:表示用户需要向方法传入的值
public class test{
public static void main(String[] args) {
//创建一个对象
Penson Penson1 = new Penson();
Penson1.speak(); //调用speak方法
Penson1.cal(5); //调用cal方法,并传入一个参数5
//调用sum方法,并传入两个参数2和3,因为返回值类型是int,所有这里用一个int变量来接收
int sum1 = Penson1.sum(2,3);
System.out.println("2和3的和为:"+sum1);
}
}
//定义一个人类,其中Penson就是自定义数据类型
class Penson{
String name; //姓名
int age; //年龄
/*
创建一个名为speak的方法
方法名:speak
访问修饰符:public 表示方法是公开的
返回值:void 无返回值
形参列表:() 无形参
*/
public void speak(){
System.out.println("Hello Java");
}
/*
创建一个cal方法,计算1到n之间的累加求和
方法名:cal
访问修饰符:public 表示方法是公开的
返回值:void 无返回值
形参列表:(int n)表示需要接受一个整型的参数
*/
public void cal(int n){
int sum = 0;
for (int i = 1; i<=n ;i++ ) {
sum += i;
}
System.out.println("1到"+n+"的和为:"+sum);
}
/*
创建一个sum方法,计算两个数的和
方法名:sum
访问修饰符:public 表示方法是公开的
返回值:int int类型的返回值
形参列表:(int n)表示需要接受一个整型的参数
*/
public int sum(int n,int m){
int sum1 = n+m;
return sum1;
}
}
3.注意事项
1.方法本身
(1)一个方法只能有一个返回值,如果想返回多可以利用数组
public class test{
public static void main(String[] args) {
test1 m = new test1();
int newArr[] = m.getSumAndSub(5,3);
System.out.println("和为:"+newArr[0]);
System.out.println("差为:"+newArr[1]);
}
}
class test1{
//返回值为数组类型,可以有多个返回值
public int[] getSumAndSub(int x,int y){
//创建一个数组
int arr[] = new int[2];
arr[0] = x + y;
arr[1] = x - y;
return arr;
}
}
(2)返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
(3)如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值; // 而且要求返回值类型必须和 return 的值类型一致或兼容
(4).当方法的返回值为void的时,retrun可以不写,或者只写return
2.参数列表
(1)一个方法可以有0个参数,或者多个参数,中间用逗号隔开
(2)参数的类型可以是基本类型或引用类型
(3)调用带参的方法时,一定对应参数列表传入相应数据类型的值
(4)方法定义时的参数叫形参,调用时的参数叫实参,且对应的类型、个数、顺序以及兼容必须一致。
4.成员方法的传参机制
1.基本数据类型传参
基本数据类型传递的参数,是值的拷贝,形参不会影响实参
public class test{
public static void main(String[] args) {
int x = 10;
int y = 20;
test1 obj = new test1();
obj.swap(x,y);
System.out.println("main中交换后的x和y的值为:"+x+" "+y); //x=10 y=20
}
}
class test1{
public void swap(int x,int y){
System.out.println("swap交换前的x和y的值为:"+x+" "+y); //x=10 y=20
//把x和y进行交换
int temp = x;
x = y;
y = temp;
System.out.println("swap交换后的x和y的值为:"+x+" "+y); //x=20 y=10
}
}
2.引用数据类型传参
引用类型传递表面是传递的是值,其实传递的是地址,是可以通过形参影响到实参的
数组为引用
public class test{
public static void main(String[] args) {
int arr[] = {1,2,3};
test1 obj = new test1();
obj.A(arr);
//实参会受到影响,随着形参改变而改变
System.out.println("修改后main方法中遍历数组");
for (int i=0;i<arr.length;i++ ) {
System.out.println(arr[i]); //10 2 3
}
}
}
class test1{
public void A(int arr[]){
System.out.println("修改前A方法中遍历数组");
for (int i=0;i<arr.length;i++ ) {
System.out.println(arr[i]); //1 2 3
}
//修改数组第一个元素的值
arr[0] = 10;
System.out.println("修改后A方法中遍历数组");
for (int i=0;i<arr.length;i++ ) {
System.out.println(arr[i]); //10 2 3
}
}
}
对象为引用
public class test{
public static void main(String[] args) {
test1 t = new test1();
Person p = new Person();
p.name = "zhangsan";
p.age = 18;
//调用方法A
t.A(p);
System.out.println(p.age); //20
//调用方法B,其值不会发生改变,因为B方法中的p和main方法中的p不是同一个对象,内存地址也不一样,
t.B(p);
System.out.println(p.age); //值不变依然是20
}
}
class Person{
String name;
int age;
}
class test1{
public void A(Person p){
p.age = 20;
}
public void B(Person p){
p = new Person();
p.age = 30;
}
}
5.对象的克隆
将一个对象的属性copy到另一个对象中去
public class test{
public static void main(String[] args) {
Person p = new Person();
p.name = "zhangsan";
p.age = 20;
test1 t = new test1();
Person p1 = t.copyPerson(p);
//p和p1是两个不同的对象,但是属性值时一样的,这就完成对象的copy
System.out.println("p的name和age为:"+p.name+" "+p.age);
System.out.println("p的name和age为:"+p1.name+" "+p1.age);
}
}
class Person{
String name;
int age;
}
class test1{
//创建一个返回值为Person的对象
public Person copyPerson(Person p){
Person p1 = new Person();
p1.name = p.name;
p1.age = p.age;
return p1;
}
}
三、方法的递归调用
1.基本介绍
递归:其实就是自己调用自己,每次传入的变量不同,递归有助于编程者解决复杂问题,同时可以让代码变得简洁
阶乘问题
public class test{
public static void main(String[] args) {
//普通方法求阶乘
int s = 1;
for (int i = 1; i<=5 ; i++ ) {
s *= i;
}
System.out.println("5的阶乘为:"+s);
//递归方法
test1 obj = new test1();
int x = obj.jc(5);
System.out.println("5的阶乘为:"+x);
}
}
class test1{
public int jc(int x){
if (x == 1) {
return 1;
}else{
return jc(x-1)*x;
}
}
}
2.注意事项
- 递归必须有退出条件,否则就会出现无限递归调用,就会死归
- 如果方法中使用引用类型变量(比如数组,对象等),就会共享该引用类型的数据
- 方法中的局部变量是独立的,不会相互影响
- 当一个方法执行完毕时,或者遇到return,这个方法就执行完毕,并且返回
3.使用递归解决经典问题
斐波那契数列问题
public class test{
public static void main(String[] args) {
//递归方法
test1 obj = new test1();
int x = obj.A(7);
System.out.println("斐波那契数列的第七项为:"+x); //值为13
}
}
class test1{
public int A(int x){
if (x>=1) {
if ( x == 1 || x == 2) {
return 1;
}else{
return A(x-1)+A(x-2);
}
}else{
System.out.println("请输入一个>=1的数");
return -1;
}
}
}
猴子吃桃子问题
假如有一堆桃子,第一天猴子吃了其中的一半,并再多吃一个,以后每天猴子都吃其中的一半,并再多吃一个,当第10天时,发现只有1个桃子了,问在第5天时还有多少个桃子
public class test{
public static void main(String[] args) {
/*
进行一个 逆推
第10天:1个桃子
第9天:4个桃子
第8天:10个桃子
第n天 = (n+1的桃子+1)*2
*/
test1 obj = new test1();
int x = obj.A(8);
System.out.println("第五天的桃子为:"+x);
}
}
class test1{
public int A(int x){
if (x == 10) {
return 1;
}else if(x>=1 || x<=9){
return (A(x+1)+1)*2;
}else{
System.out.println("请输入1-10之内的天数");
return -1;
}
}
}
老鼠出迷宫问题
public class test{
public static void main(String[] args) {
/*
第一步:创建一个长8宽8的迷宫,使用二维数组并赋值,0表示可通,1表示不通
1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1
1 1 1 1 1 0 0 1
1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1
*/
int arr[][] = new int[8][8];
for (int i = 0; i<8 ; i++) {
for (int j = 0 ; j<8 ; j++ ) {
if (i == 0 || i == 7) {
arr[i][j] = 1;
}
}
}
for (int i = 0; i<8 ; i++) {
for (int j = 0 ; j<8 ; j++ ) {
if (j == 0 || j == 7) {
arr[i][j] = 1;
}
}
}
arr[3][1] = 1;
arr[3][2] = 1;
arr[3][3] = 1;
arr[3][4] = 1;
//二维数组的遍历
for (int i = 0; i<8 ; i++) {
for (int j = 0 ; j<8 ; j++ ) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
//创建findWay对象,开始找路
test1 t = new test1();
boolean f = t.findWay(arr,1,1);
System.out.println("======小老鼠找到出口路径======");
for (int i = 0; i<8 ; i++) {
for (int j = 0 ; j<8 ; j++ ) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
/*
1 1 1 1 1 1 1 1
1 2 0 0 0 0 0 1
1 2 2 2 2 2 0 1
1 1 1 1 1 2 0 1
1 0 0 0 0 2 0 1
1 0 0 0 0 2 0 1
1 0 0 0 0 2 2 1
1 1 1 1 1 1 1 1
*/
}
}
/*
1.小老鼠初始位置是不确定的,出口的位置为arr[6][5]
2.如果找到出口返回true,否则返回false
3.其中数组元素为0表示可通,1表示不通,2表示小老鼠顺利到出口的路径,3表示走过但是没有走通
4.当arr[6][5] = 2时,则说明找到出口结束,否则继续找
5.确定老师找路的方法:首先从下开始走,如果下面走不通,就往右走,依次顺序为下->右->上->左
*/
class test1{
public boolean findWay(int arr[][],int i,int j){
if (arr[6][6] == 2) {
return true;
}else{
if (arr[i][j] == 0) { //等于0说明可以走
//假设可以走我就设置当前数组元素为2
arr[i][j] = 2;
//通过找路的方法进行判断是否可以走通
if (findWay(arr,i+1,j)) { //往下走
return true;
}else if (findWay(arr,i,j+1)) { //右
return true;
}else if (findWay(arr,i-1,j)) { //上
return true;
}else if (findWay(arr,i,j-1)) { //左
return true;
}else {
//如果上下左右都走不通则说明当前位置为死路,也就是小老鼠走不出迷宫
arr[i][j] = 3;
return false;
}
}else{
return false;
}
}
}
}
汉诺塔问题
将下图A塔中所有的盘子,搬运到B塔或者C塔中
要求:
1.每次只能搬运一个盘子
2.最终搬完以后的顺序和A塔的顺序一样
public class test{
public static void main(String[] args) {
test1 t = new test1();
t.move(3,'a','b','c');
}
}
class test1{
//num表示移动的次数,a,b,c分别代表A塔B塔C塔
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);
System.out.println(a + "塔 到 " + b + "塔");
//再把B塔上面所有的盘子到C塔,需要借助A塔
move( num-1,b,a,c);
}
}
}