day07.可变参数 命令行参数 递归 对象数组
课前回顾:
1.面向对象:Java语言的核心变成思想,自己的事情自己不做,找别人帮我去做事
2.为什么要使用面向对象思想编程:
为了让编写过程更简单(很多的功能别人都已经封装好了,不用我们自己一步一步的写,直接调用,就能完成想要的功能)
3.什么情况下使用面向对象思想:
在一个类中使用别的类的成员时,就需要new对象 点方法(new对象,点方法的过程就是在使用面向对象的过程)
4.怎么用?
new 对象 点方法
5.类和对象
类:
属性(成员变量)
行为(成员方法(不带static的))
对象:一类事物的具体体现
导包:import 包名.类名
两个类不在同一个包下,需要导包
在同一个包下,不用导包了
lang包下类使用时无需导包
创建对象:想使用哪个类中的成员,就new哪个类的对象
类名 对象名 = new 类名()
调用成员(成员方法,成员变量):想调用哪个成员,就用哪个对象去点哪个成员
对象名.成员变量 = 值
对象名.成员方法(参数)
6.成员变量和局部变量的区别:
a.定义位置
成员变量:定义在类中方法外
局部变量:定义在方法内部或者参数位置
b.作用范围
成员变量:作用于整个类
局部变量:只作用于自己的方法中
c.默认值
成员:有默认值的
局部:没有默认值,不手动赋值,不能直接使用
d.在内存中的位置
成员:在堆中
局部:在栈中
e.生命周期不同
成员:随着对象的创建而存在,随着对象的消失而消失
局部:随着方法被调用而产生,随着方法调用完毕而消失
7.static:静态
a.被static修饰的成员,属于类,随着类的加载而加载
b.非static的属于对象,所以static的成员优先于非静态成员存在的
c.只要是根据static所在的类创建出来的对象,都可以共享这个static成员
d.访问:类名直接调用
今日重点:
1.会使用可变参数定义方法
2.会简单使用递归
3.会往数组中存储对象,遍历数组,获取每一个对象中的属性值
4.会二分查找法
第一章.可变参数
1介绍和基本使用
1.需求:定义一个方法,实现若干个整数相加(参数类型确定,个数不确定)
2.可变参数什么时候使用:
当定义方法时,参数类型确定,但是个数不确定
3.格式:
数据类型...变量名
4.可变参数的本质:
数组
5.注意事项:
a.参数位置只能出现一个可变参数
b.如果可变参数和其他的普通参数一起出现,可变参数放在最后面
public class Test01 {
public static void main(String[] args) {
sum(1,2,3,4,5,6,6,5,6,4,5,7);
}
public static void sum(int...arr){
//定义一个变量sum接收两个数的和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum+=arr[i];
}
System.out.println(sum);
}
}
Collections类中的方法:
static <T> boolean addAll(Collection<? super T> c, T... elements)->将elements代表的元素批量放到c代表的集合中
public class Test02 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
Collections.addAll(list,"涛哥","柳岩","金莲","武松");
System.out.println(list);
}
}
2可变参数
在JDK1.5之后,如果我们定义一个方法时,此时某个形参的类型可以确定,但是形参的个数不确定,那么我们可以使用可变参数。
格式:
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){ }
要求:
(1)一个方法最多只能有一个可变参数
(2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个
(3)其实这个书写“≈”
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){ }
只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,这样更灵活了。
示例二:求n个整数的和
public class Test01 {
public static void main(String[] args) {
sum(1,2,3,4,5,6,6,5,6,4,5,7);
}
public static void sum(int...arr){
//定义一个变量sum接收两个数的和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum+=arr[i];
}
System.out.println(sum);
}
}
示例二:字符串拼接
需求一:返回n个字符串拼接结果,如果没有传入字符串,那么返回空字符串””
public class Test03 {
public static void main(String[] args) {
String concat = concat("hello", "world", "柳岩", "最美");
System.out.println(concat);
}
public static String concat(String...arr){
//定义一个str,用于接收两个字符串拼接的结果
String str = "";
for (int i = 0; i < arr.length; i++) {
str+=arr[i];
}
return str;
}
}
需求二:n个字符串进行拼接,每一个字符串之间使用某字符进行分隔,如果没有传入字符串,那么返回空字符串””
调用方法:
concat(",","hello","world")-> hello,world
public class Test04 {
public static void main(String[] args) {
String concat = concat(",", "hello", "world");
System.out.println(concat);
}
public static String concat(String s,String...arr){
String str = "";
for (int i = 0; i < arr.length; i++) {
if (i==arr.length-1){
// str = str+arr[i];
str+=arr[i];
}else{
//str = str+arr[i]+s;
str+=arr[i]+s;
}
}
return str;
}
}
第二章.递归
1.从前有座山,山上有座庙,庙里有个老和尚,老和尚跟小和尚讲故事,讲的啥呢?
从前有座山,山上有座庙,庙里有个老和尚,老和尚跟小和尚讲故事,讲的啥呢?
从前有座山,山上有座庙,庙里有个老和尚,老和尚跟小和尚讲故事,讲的啥呢?
2.递归概述:
方法内部自己调用自己->直接递归
public static void method(){
method();
}
方法之间互相调用->间接递归
public static void method1(){
method2();
}
public static void method2(){
method3();
}
public static void method3(){
method1();
}
3.注意:
递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出(因为会不断的压栈)。
在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
3.1 递归
- 递归:指在当前方法内调用自己的这种现象。
- 递归的分类:
- 递归分为两种,直接递归和间接递归。
- 直接递归称为方法自身调用自己。
- 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。
注意事项:
- 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出(因为会不断的压栈)。
- 在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
示例一:需求:利用递归输出3到1
public class Test01 {
public static void main(String[] args) {
method(3);
}
public static void method(int n) {
System.out.println(n);
n--;
if (n==1){
System.out.println(1);
//结束方法
return;
}
method(n);
}
}
示例二:求n!
1.定义一个方法f() 表示 阶乘方法
2.分析过程
f(1): 1
f(2): 1*2-> f(1)*2
f(3): 1*2*3->f(2)*3
f(4): 1*2*3*4->f(3)*4
f(5): 1*2*3*4*5->f(4)*5
....
总结规律: f(n) = f(n-1)*n
public class Test02 {
public static void main(String[] args) {
int result = f(5);
System.out.println(result);
}
/*
f(1): 1
f(2): 1*2-> f(1)*2
f(3): 1*2*3->f(2)*3
f(4): 1*2*3*4->f(3)*4
f(5): 1*2*3*4*5->f(4)*5
....
总结规律: f(n) = f(n-1)*n
*/
public static int f(int n){
if (n==1){
return 1;
}
return f(n-1)*n;
}
}
示例三:计算斐波那契数列(Fibonacci)的第n个值
不死神兔
故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契。
在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔,再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,一年内没有发生死亡
问:一对刚出生的兔子,一年内繁殖成多少对兔子?144
规律:一个数等于前两个数之和,比如: 1 1 2 3 5 8 13 21 34 55….
定义一个方法f 代表递归方法,传递的参数代表月份
f(1) : 1
f(2) : 1
f(3) : 2 f(1)+f(2)
f(4) : 3 f(2)+f(3)
f(5) : 5 f(3)+f(4)
总结:
问第n个月,有多少对兔子
f(n-2)+f(n-1)
public class Test03 {
public static void main(String[] args) {
int result = f(12);
System.out.println(result);
}
public static int f(int n){
if (n==1 || n==2){
return 1;
}
return f(n-2)+f(n-1);
}
}
第三章 对象数组
需求:定义一个长度为3的数组,存储3个Person对象 遍历数组,将Person对象的属性值获取出来
public class Person {
String name;
int age;
}
public class Test01 {
public static void main(String[] args) {
/*
1.定义数组,长度为3
Person p = new Person()->Person类型
Person[] arr = new Person[3]
"abc"->String类型
String[] arr = new String[3]
1->int类型
int[] arr = new int[3]
2.5->double类型
double[] arr = new double[3]
*/
/*
创建一个专门存储Person对象的数组,
由于数组中的Person对象数据类型为Person类型
所以,我们定义数组时就写Person[]
*/
Person[] arr = new Person[3];
//创建3个Person对象
Person p1 = new Person();
p1.name = "柳岩";
p1.age = 36;
Person p2 = new Person();
p2.name = "金莲";
p2.age = 26;
Person p3 = new Person();
p3.name = "杨幂";
p3.age = 32;
//将三个对象存储到数组中
arr[0] = p1;
arr[1] = p2;
arr[2] = p3;
//遍历
/*
第一次循环: i = 0 arr[i]->arr[0]->p1
p1.name = "柳岩"
p1.age = 36
第二次循环: i = 1 arr[i]->arr[1]->p2
第三次循环: i = 2 arr[i]->arr[2]->p3
*/
for (int i = 0; i < arr.length; i++) {
Person p = arr[i];
System.out.println(p.name+"..."+p.age);
}
}
}
数组是用来存储一组数据的容器,一组基本数据类型的数据可以用数组装,那么一组对象也可以使用数组来装。
即数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用数据类型时,我们称为对象数组。
注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。
练习1
(1)定义学生类Student
声明姓名和成绩实例变量
(2)测试类ObjectArrayTest的main中创建一个可以装3个学生对象的数组,并且按照学生成绩排序,显示学生信息
public class Student {
String name;
int score;
}
public class Test02_Student {
public static void main(String[] args) {
//1.创建长度为3的数组
Student[] students = new Student[3];
//2.创建3个Student对象
Student s1 = new Student();
s1.name = "柳岩";
s1.score = 36;
Student s2 = new Student();
s2.name = "金莲";
s2.score = 26;
Student s3 = new Student();
s3.name = "涛哥";
s3.score = 100;
//3.将三个对象,存储到数组中
students[0] = s1;
students[1] = s2;
students[2] = s3;
//4.根据成绩排序
for (int j = 0;j<students.length-1;j++){
for (int i = 0; i < students.length-1-j; i++) {
if (students[i].score>students[i+1].score){
Student temp = students[i];
students[i] = students[i+1];
students[i+1] = temp;
}
}
}
//5.遍历
for (int i = 0; i < students.length; i++) {
System.out.println(students[i].name+"..."+students[i].score);
}
}
}
第四章.二分查找
1.前提:数组元素是有序
2.怎么查:一次干掉一半这种方式去查询
public class Test01 {
public static void main(String[] args) {
//定义数组
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
//定义min 和max 分别代表数组的最小索引和最大索引
int min = 0;
int max = arr.length - 1;
//定义mid,代表中间索引
int mid = 0;
//明确要查找的数据
int key = 0;
while(min<=max){
//计算出中间索引
mid = (min+max)/2;
if (key>arr[mid]){
min = mid+1;
}else if (key<arr[mid]){
max = mid-1;
}else{
System.out.println(mid);
return;//结束方法
}
}
System.out.println(-1);
}
}
第五章.数组翻转
1.对称索引位置上的元素互换位置
public class Test01 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8};
for (int min = 0,max = arr.length-1;min<max;min++,max--){
int temp = arr[min];
arr[min] = arr[max];
arr[max] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
第六章.命令行参数(了解)
通过命令行给main方法的形参传递的实参称为命令行参数
public class TestCommandParam{
//形参:String[] args
public static void main(String[] args){
for(int i=0; i<args.length; i++){
System.out.println("第" + (i+1) + "个参数的值是:" + args[i]);
}
}
}
运行命令:
java TestCommandParam
java TestCommandParam 1 2 3
java TestCommandParam hello atguigu
第七章.API文档的使用
1.API概述:定义好的类以及接口以及类和接口中的方法
2.API文档:是我们程序员的"字典"
1.查找想要使用的API
2.看对应API的成员
第八章.封装
1.封装的介绍和基本使用
1.面向对象的三个特征: 封装 继承 多态
2.概述:
a.为什么需要封装?封装的作用和含义?
我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
b.隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
将细节隐藏起来,对外提供一个暴露的接口,供我们使用者使用,我们只需要调用这个接口,接口中的细节(代码)就执行起来了
3.考虑的问题:不是说private(私有的权限修饰符)就代表了所有的封装
将代码放到一个代码块中也可以称之为封装
4.关键字(在封装思想中比较有代表性的)
a.private-> 私有权限
b.修饰一个成员变量: private 数据类型 变量名
修饰一个成员方法: private 返回值类型 方法名(参数){}
c.私有的成员,只能当前类使用,别的类中不能直接使用
5.问题:
a.当一个成员被private修饰,外界彻底使用不了了,我们使用private将细节隐藏起来,我们还需要将接口暴露出来供别人使用
b.被private修饰的成员变量,需要提供对应的getxxx/setxxx方法来为private修饰的成员变量赋值.取值
c.getxxx()获取属性值
setxxx()为属性赋值
public class Person {
private String name;
//隐藏细节->封装思想
private int age;
//对外提供可使用的接口
public void setAge(int nianLing){
if (nianLing<0){
System.out.println("你疯了,你没了");
}else{
age = nianLing;
}
}
public int getAge(){
return age;
}
public void setName(String xingMing){
name = xingMing;
}
public String getName(){
return name;
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
//person.name = "狗剩";
person.setName("狗剩");
//person.age = 18;
person.setAge(18);
System.out.println(person.getName()+"..."+person.getAge());
}
}