1. 类与对象 1.1 类和对象的区别和联系
1.2 类的属性和成员变量
成员变量是用来表示属性的,即 : 成员变量 = 属性 = field
属性是类的一个组成部分,可以为任意类型,包含基本类型或引用类型(对象,数组等)
比如 1.2 中定义的猫类的 age 就是属性
属性的定义语法与变量相同 访问修饰符 属性类型 属性名;
访问修饰符为: public,proctected ,private,默认(不使用访问修饰符)
类型
默认值
byte, short, int, long
0
float, double
0.0
char
\u0000
boolean
false
其它引用类型
null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class PropletiesDetail { public static void main (String args[]) { Person p1 = new Person (); } } class Person { int age; String name; double sal; boolean isPass; }
1.3 创建对象的方式 1 2 3 4 5 6 Cat cat; cat = new Cat (); Cat cat = new Cat ();
1.4 类和对象的内存分配机制 Java 内存有几下几个重要的部分组成
栈: 一般存放基本数据类型的数据(局部变量)
堆: 存放引用类型的数据(对象,数组)等
方法区: 常量池(常量,比如字符串),类加载信息等
1 2 3 4 5 Cat cat = new Cat ();cat.name = "汤姆" ; cat.age = 100 ; cat.color = "blue" ;
1 2 3 4 5 6 7 Persion p1 = new Persion ();p1.name = "小明" ; p1.age = 10 ; Persion p2 = new Persion ();p2 = p1; System.out.println(p2.age)
1.5 创建对象的流程 1 2 3 4 5 6 7 8 Person p = new Person ();p.name = "小明" ; p.age = 10 ;
2. 成员方法介绍 2.1 基本介绍 在某些情况下,我们需要定义成员方法,
比如人类: 除了有一些属性(年龄、姓名)外,还有一些行为,比如可以说话、 跑步等,
这时就要用成员方法才能完成,现在要求对 person 类进行完善
成员方法可以提高代码的复用性,还可以将实现的细节封装起来,然后供其他用户来调用
2.2 成员方法的定义
访问修饰符:用来控制方法的使用范围, 如果不写则使用默认访问范围, 一共有四种(public, protected,无修饰符(默认),private)
形参列表:表示成员方法输入参数
返回数据类型:表示成员方法运行完成之后输出的数据类型, 当返回数据类型位置上为 void 时, 表示没有返回值
方法主体:表示为了实现方法功能的代码块
return 语句:表示方法返回的数据, 与返回数据类型需一直, 当没有返回值时, 则不需要 return 语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 访问修饰符 返回数据类型 方法名(形参列表 ... ){ 语句 1 ; 语句 2 ; ... return 返回值 } public int sum (int a,int b) { int c = a+b; return c; }
2.3 返回数据类型
一个方法最多有一个返回值,如果想返回多个值, 可以使用数组,集合等
方法的返回值可以为任意类型,包含基本数据类型和引用数据类型
如果方法要求有返回数据值,则方法体中最后一条执行语句必须为: return 返回值;
要求返回值类型必须和 return 的值类型一致或兼容
如果方法返回类型位置为 void,则方法体中可以不写 return 语句,或者只写 return;
1 2 3 4 5 6 7 8 9 10 11 12 public int sum (int a,int b) { int c = a+b; return c; } public void say (String name) { System.out.println("My name is " + name) }
2.4 方法命名规则 方法命名规则与标识符命名规则基本相同,但是在符合规则的情况下最好使用驼峰法命名,最好见名知意,表达出该方法功能的意思.
方法命名注意遵循以下规则:
方法名可以由26 个英文字母, 数字 0~9, 下划线 _ ,美元 $ 符号组成, 但是不能以数字开头
方法名不能是 Java 关键字和保留字, 但关键字和保留字可以作为方法名的一部分
方法名只能包含美元符号 $ 不能包含 @,# 等特殊符号.
方法名不能包含空格
Java中严格区字母分大小写
方法名长度无限制, 但是一般不建议使用过长的方法名
1 2 3 4 5 6 7 8 9 10 11 12 13 public void extends () { }public void 1hello(){ }public void hello$(){ }public void hello@(){ }public void hello_ () { }public void _hello () { }
2.5 形参列表
一个方法可以有 0 到多个参数,形参之间用逗号分隔
参数类型可以为任意数据类型,包括基本类型或引用数据类型
方法定义时设置的参数称为形式参数,简称形参
方法调用时传入的参数称为实际参数,简称实参
调用带参数的方法时,实参与形参的类型需要一致或兼容,参数个数、参数顺序必须一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Method03 { public static void main (String[] args) { Method03 method03 = new Method03 (); int a = 10 ; boolean b = false ; String c = "hello" ; method03.test(a,b,c); method03.test(a); method03.test(c,b,a); } public void test (int a,boolean b,String c) { System.out.println("a = " +a+", b= " +b+", c= " +c); } }
2.6 方法体
1 2 3 4 public void test (int a,boolean b,String c) { System.out.println("a = " +a+", b= " +b+", c= " +c); }
2.7 成员方法使用示例
同一个类中的方法之间调用,可以直接调用,比如 print(参数)
跨类中的方法调用,需要通过对象名调用,比如: 对象名.方法名(参数列表)
特别说明一下: 跨类的方法调用和方法的访问修饰符相关,后面讲到访问修饰符时会详细说明
添加 speak 方法,输出 “你好”
添加 sum01 方法,可以计算 1+2+3…+1000 的结果
添加 sum02 方法,接收一个参数,计算 1+2+…+n 的结果
添加一个 sum 方法,计算两个数的和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 public class Method01 { public static void main (String args[]) { Person person = new Person (); person.speak(); person.sum01(); person.sum02(100 ); int result = person.sum(1 ,2 ); System.out.println(result); } } class Person { String name; int age; public void open () { System.out.println("先张嘴再说话" ); } public void speak () { open(); System.out.println("你好" ); } public void sum01 () { int sum = 0 ; for (int i = 0 ; i <= 1000 ; i++) { sum +=i; } System.out.println("sum01=>" +sum); } public void sum02 (int x) { int sum = 0 ; for (int i = 0 ; i <= x; i++) { sum +=i; } System.out.println("sum02=>" +sum); } public int sum (int x,int y) { int result = x+y; return result; } }
2.8 调用方法的原理
当程序执行到方法时,就会开辟一个独立的栈空间
当方法执行完毕,或者执行到 return 语句时,就会将结果返回到调用方法的地方
被调用的方法返回后,继续执行后续代码
当 main 方法执行完成后,整个程序退出
2.9 基本类型参数传递 方法的参数传递时,基本类型的参数传递是值拷贝,形参的改变不影响实参的具体值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Method02 { public static void main (String args[]) { A a = new A (); int i = 1 ,j = 3 ; a.swap(1 ,3 ); System.out.println("main 方法: i= " +i+", j= " +j); } static class A { public void swap (int i,int j) { System.out.println("交换前: i= " +i+", j= " +j); int tmp = i; i = j; j = tmp; System.out.println("交换后: i= " +i+", j= " +j); } } }
2.10 引用类型参数传递 引用类型参数传递是地址传递,在对形参进行修改时会影响到实参
引用类型参数传递后,形参与实参仍是两个不同的引用变量,但是指向相同的实体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Method02 { public static void main (String args[]) { int arr[] = {1 ,2 ,3 }; A a = new A (); a.param(arr); System.out.println("main 函数" ); for (int k = 0 ; k < arr.length; k++) { System.out.print(arr[k]+", " ); } } static class A { public void param (int [] arr) { System.out.println("修改数组前" ); for (int k = 0 ; k < arr.length; k++) { System.out.print(arr[k]+", " ); } arr[0 ] = 100 ; System.out.println("修改数组后" ); for (int k = 0 ; k < arr.length; k++) { System.out.print(arr[k]+", " ); } } } }
3. 方法递归调用 3.1 递归的介绍
递归可以应用于各种数学问题,如 8 皇后问题,汉诺塔问题,阶乘问题,迷宫问题,球和篮子的问题等
各种算法中也会使用到递归,如快速排序,归并排序,二分法查找,分治算法等
将用栈解决的问题 ,递归代码比较简洁
3.2 递归的规则
递归执行一个新的方法时,就创建一个新的受保护的独立栈空间
方法的局部变量在自己的栈内,也就是独立的,不同方法的变量不会相互影响
如果方法中使用的是引用变量(比如数组),就会共享该引用类型的数据
递归必须向退出递归的条件逼近,否则就会出现无限递归,会出现 StackOverflowError
当一个方法执行完毕,或者遇到 return,就会返回,遵守谁调用就将结果返回给谁的原则
当方法执行完毕或者返回时,该方法就执行结束
3.3 方法递归调用 1 2 3 4 5 6 7 8 9 10 11 12 13 public class Recursion { public static void main (String args[]) { Recursion recursion = new Recursion (); recursion.test(4 ); } public void test (int n) { if (n >2 ){ test(n-1 ); } System.out.println("n = " + n); } }
3.4 递归计算阶乘 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Recursion { public static void main (String args[]) { Recursion recursion = new Recursion (); int result = recursion.factorial(2 ); System.out.println(result); } public int factorial (int n) { if (n == 1 ){ return 1 ; }else { return factorial(n-1 )*n; } } }
3.5 递归练习
有一堆桃子,猴子第一天吃了其中的一半,并且再多吃一个,以后每天都吃了一半再多吃一个,当到第 10 天时,想再吃,发现只有 1 个桃子了,问最初一共有多少桃子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class Test02Peaches { public static void main (String args[]) { for (int i = 1 ; i <= 10 ; i++) { System.out.println("第 " +i+" 天 桃子数量为: " +count(i)); } } public static int count (int day) { if (day == 10 ){ return 1 ; }else { return (count(day+1 )+1 )*2 ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Fibonacci { public static void main (String args[]) { for (int i=1 ;i<10 ;i++){ System.out.println(getFibonacci(i)); } } public static long getFibonacci (int n) { if (n>=1 ){ if (n == 1 || n ==2 ){ return 1 ; }else { return getFibonacci(n-1 )+getFibonacci(n-2 ); } } return 0 ; } }
4. 方法重载 Java 中允许同一个类中写多个同名方法,这些方法就构成了重载,方法的重载还有以下详细的要求:
方法名称:必须相同
形参列表:形参的数据类型 或 形参个数 至少 有一样不同,对于形参名称没有要求
返回类型:无要求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class Overload01 { public static void main (String args[]) { Overload01 o = new Overload01 (); int a = o.sum(1 , 2 ); System.out.println("a = " + a); double b = o.sum(10.1 , 2 ); System.out.println("b = " + b); double c = o.sum(9.9 , 3.3 ); System.out.println("c = " + c); int d = o.sum(1 , 2 , 3 ); System.out.println("d = " + d); } public int sum (int a, int b) { return a + b; } public double sum (double a, int b) { return a + b; } public double sum (double a, double b) { return a + b; } public int sum (int a, int b, int c) { return a + b; } }
编写程序,类 Overload02 中定义三个重载方法并调用,方法名为 m
第一个 m 方法接收一个 int 参数,输出 平方 信息
第二个 m 方法接收两个 int 参数,输出 求和 信息
第三个 m 方法接收字符串,并打印该 字符串 信息
在 Overload02 类中定义 max 方法的重载,
第一个 max 方法, 返回 两个 int 数据的最大值
第二个 max 方法, 返回 两个 double 数据的最大值
第三个 max 方法, 返回 三个 double 数据的最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class Overload02 { public static void main (String args[]) { Overload02 o = new Overload02 (); System.out.println(o.m(9 )); System.out.println(o.m(9 , 2 )); o.m("hello" ); System.out.println(o.max(1 , 2 )); System.out.println(o.max(1.0 , 2.0 )); System.out.println(o.max(1.0 , 2.0 , 3.0 )); } public int max (int a, int b) { if (a > b) { return a; } else { return b; } } public double max (double a, double b) { if (a > b) { return a; } else { return b; } } public double max (double a, double b, double c) { double m = a > b ? a : b; m = m > c ? m : c; return m; } public int m (int a) { return a * a; } public int m (int a, int b) { return a + b; } public void m (String str) { System.out.println(str); } }
5. 方法的可变参数 Java 中的方法,可以将形参中 多个 同类型的形参 合并成一个形参,这种情况就是 可变参数
1 2 3 4 5 6 7 8 public void methodName (int ... arrs) { }
可变参数的实参可以为 0 到任意多个
可变参数的实参可以为数组
可变参数的本质就是数组
可变参数可以和普通参数一起放在形参列表中,但必须保证可变参数在最后一位
一个形参列表中最多 只能 定义 一个 可变参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class VarParameter01 { public static void main (String args[]) { VarParameter01 v = new VarParameter01 (); System.out.println("累加和 为: " + v.sum(1 , 2 , 3 )); System.out.println(v.score("小明" , 90 , 98 , 2 )); } public int sum (int ... nums) { System.out.println("参数个数" + nums.length); int result = 0 ; for (int i : nums) { result += i; } return result; } public String score (String name, int ... socres) { System.out.println("科目数" + socres.length); int total = 0 ; for (int i : socres) { total += i; } return name + " 总分数:" + total; } }
6. 作用域
作用域是指变量的有效范围,在一个方法中能够访问到该变量,就说明方法在变量的有效作用域中
Java 中根据变量的定义位置不同,作用域也有很大的差别,如:
全局变量,即成员属性,作用域为整个类
局部变量,也就是除了成员属性之外的变量,一般是在方法中定义的变量,其作用域为定义它的代码块中
全局变量和局部变量可以重名,访问同名变量时,遵循就近原则
在同一个作用域中的两个变量不能重名
全局变量
局部变量
默认值
如果没有显式赋值则系统赋默认值
必须显式赋值
作用域
整个类
所在的方法或代码块
生命周期
伴随着对象的声明而创建,对象的销毁而销毁
跟所在的方法或代码块一致,(一次方法的调用)
访问
可以被本类和其他类访问
只能在本类对应的方法中使用
修饰符
可以加访问修饰符
不可以加访问修饰符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class VarScope { public static void main (String args[]) { Cat cat = new Cat (); cat.hi(); cat.eat(); cat.rename(); } } class Cat { String name = "tom" ; int age; public void hi () { age = 10 ; char gender = 'M' ; System.out.println("name = " + name+", age = " + age+", gender = " + gender); } public void eat () { String food = "jerry" ; System.out.println(name +" 喜欢吃 " + food); } public void rename () { String name = "jerry" ; System.out.println("name = " + name+", age = " + age); } }
7. 构造方法
构造方法,又称 构造函数 或 构造器(constructor) ,是类的一种特殊方法,它的主要作用是完成对新对象的初始化
构造方法名和类名必须相同
构造方法没有返回值
构造方法的调用由系统自动完成
构造方法的修饰符可以使用 public,protected,默认修饰符 或 private
构造方法可以有 0 到多个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 访问修饰符 方法名(形参列表 ... ){ 语句 1 ; 语句 2 ; } public Cat (String name,int age) { this .name = name; this ,age = age; }
在创建人类时,直接指定这个对象的年龄和姓名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Constructor01 { public static void main (String args[]) { Person01 xiaom = new Person01 ("xiaom" , 18 ); } } class Person01 { String name; int age; public Person01 (String name, int age) { this .name = name; this .age = age; } }
构造方法可以重载,即一个类可以定义多个参数不同的构造方法
构造方法主要作用是完成对象的初始化,并不是创建对象
创建对象时,系统会自动调用该类的构造器完成对对象的初始化
如果没有自定义构造方法,那么系统会添加一个默认无参的构造方法
如果自定义了构造方法,那么系统便不会添加默认的构造方法,除非显式的定义一个无参的构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class Constructor01 { public static void main (String args[]) { Person01 p1 = new Person01 ("小明" , 18 ); Person01 p2 = new Person01 ("小雪" ); Person01 p3 = new Person01 (); } } class Person01 { String name; int age; public Person01 () {} public Person01 (String name, int age) { this .name = name; this .age = age; } public Person01 (String name) { this .name = name; } }
8. 对象创建流程 1 2 3 4 5 6 7 8 9 class Person { int age = 90 ; String name; Person(String name, int age){ this .name = name; this .age = age; } } Person P = new Person ("阿花" ,18 );
9. this 关键字
Java 虚拟机会给每个对象分配一个 this,代表当前对象
简单的说哪个对象使用this调用属性或方法,那么这个对象就是 this
this 关键字可以用来访问本类的属性,方法,构造器等
this 用来区分当前类的属性和局部变量
使用 this 访问成员方法,this.方法名(参数列表)
使用 this 访问构造方法,this(参数列表),只能在一个构造器中使用 this 访问另外一个构造器
不能在成员方法中使用 this 访问构造方法
this 只能在类定义的方法中使用,不能再类定义的外部使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class This02 { public static void main (String args[]) { Animal animal = new Animal (); System.out.println("animal.hashCode() " + animal.hashCode()); animal.say(); } } class Animal { public void say () { System.out.println("this.hashCode() " +this .hashCode());; System.out.println("动物叫" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public class This01 { public static void main (String args[]) { Person02 person02 = new Person02 (); person02.method02(); Person02 person03 = new Person02 ("小花" , 20 ); System.out.println(person03.toString()); } } class Person02 { String name; int age; public void method01 () { System.out.println("method01" ); } public void method02 () { System.out.println("method02" ); method01(); this .method01(); } Person02() {} Person02(String name) { this .name = name; } Person02(String name, int age) { this (name); this .age = age; } @Override public String toString () { return "Person02{" + "name='" + name + '\'' + ", age=" + age + '}' ; } }