文章目录
1) 基础语法
1.1) 注释
作用:为程序做解释(类似说明书)帮助自己或他人理解自己写的代码到底是如何运行的,从而有效降低屎山代码的出现.虽然,不写注释可以在离职之后让前公司来求你,但是为了防止上午写的程序下午就忘记写到哪了的事情发生,请各位要养成写注释的好习惯.(tips:注释中的文字都不会被程序运行,所以写什么都ok.)
- 单行注释
//本行双斜杠后的都视为注释
- 多行注释
/*杠星与星杠之间都为多行注释 /* 杠星与星杠之间都为多行注释 杠星与星杠之间都为多行注释 多行注释嵌套后首个杠星与首个星杠之间视为注释 */(多行注释到此结束) */(←被视为多余的*/)
public class Main { public static void main(String[] /*多行注释可以想这样做行内注释,但单行注释不行*/args){ System.out.println("小贴士"); } }
- 文档注释
/**
* @author 作者
* @version 1.0
*/
public class Main {
public static void main(String[] args){
System.out.println("Hello World");
}
}
1.2) 标识符
- 作用:给变量、类、方法、以及包进行命名.
- 规则:
- 必须以字母、下划线、$符号开头.
- 其余部分可以用字母、下划线、$符号和字母以任意方式组合
- 不能用Java关键字(关键字较多不需要现在记忆 往后学习会逐一认识)
- 标识符规范(也被称为驼峰规则):
- 表示类的标识符的每个首字母大写,如 Number, GoodFriend
- 表示方法和变量的标识符的第一个单词首字母小写,第二个单词首字母大写,如 music(), musicTeacher()
1.3) 变量
- 变量的基本要素:类型+名称+值
示例:
public class Main {
public static void main(String[] args){
int a=1;//定义了一个变量,类型为int整型,名称a,值1
int b=2;//定义了一个变量,类型为int整型,名称b,值2
b=81;//把81的值赋给了b变量
System.out.println(a);//输出a变量的值
System.out.println(b);//输出b变量的值
}
}
- 注意事项
- 变量表示内存中一个存储区域,不同类型的变量占用空间(字节)不同
- 该区域有自己的变量名和数据类型
- 变量必须先声明,后使用,顺序不可调换
- 变量可在同一数据类型范围内不断变化
- 变量不能在同一作用域内重名(即不能重复定义同一变量名)
- 变量=变量名+值+数据类型
1.4) 数据类型
- 基本数据类型
- 数值型
- 整数类型(存放整数[所占字节]):byte[1],short[2],int[4],long[8]
- 浮点类型(存放小数):float[4],double[8]
- java 的整数常量默认为int 声明long型常量需在后加’l’或’L’
- java 的浮点常量默认为double 声明float型常量需在后加’f’或’F’
- 在赋值时要注意以上两点避免数据丢失
- 浮点型常量表示形式:
十进制: 3.14 314.1f .314(零点几的小数 零可以省略 小数点不能省)
科学计数法: 3.14e2[3.14*10的2次方] 3.14E-2[3.14/10的2次方]
- 尽量不要用运算结果是小数的数与其他数进行相等判断(如:5.1/3==1.7) 可以将两数的差值的绝对值与某个小数比较(如:Math.abs(5.1/3-1.7)<1E-6)
- 字符型
- char[2],存放单个字符 ‘b’
- 字符常量是用(’ ')括起来的单个字符.如: char a1=‘a’; char a2=‘b’
- 转义字符是用反斜杠(\)表示,作用是用来转义后面一个字符,转移后的字符通常用来表示一个不可见的字符或者有特殊作用的字符(如:'\n’表示换行符)\和其后字符一起构成一个转义字符
- java中char的本质是整数,在输出时,是unicode码对应的字符
- char[2],存放单个字符 ‘b’
- 布尔型
- boolean[1],存放 true,false
- 适用于逻辑运算,一般用于程序控制流程
- boolean[1],存放 true,false
- 引用数据类型
- 类
- class
- 接口
- interface
- 数组
- []
2) 运算符
2.1) 算术运算符
- 类型:+,-,*,/,%,++,–
- +,-,*,/与数学中的符号意思相同 不做过多解释(只有整数型之间进行除法运算时会直接舍去小数位,不会四舍五入 如:5/2=2)
- %即为取除法后的余数,如:7%3=1, -7%3=-1
- ++即为自增,n++等价于n=n+1,++n也等价于n=n+1
n++为先赋值再自增;++n为先自增再赋值
示例
int a=2;
a++;
System.out.println(a);
++a;
System.out.println(a);
System.out.println(a++);//先输出再+1
System.out.println(++a);//先+1再输出
结果:
3
4
4
6
2.2) 关系运算符
介绍:关系运算符的结果都为boolean类型,即结果要么为true要么为false
- 关系运算符
==(相等),!=(不等于),<,>,<=,>=(单个’='是赋值运算符)
(与数学符号用法基本相同不做过多解释)
2.3) 逻辑运算符
- 与 &,&&(当两边结果都为true时结果为true)
- 或 |,||(当两边结果有一边为true时结果为true)
- 非 !a(当a为false时结果为true)
- 异或 a^b(当ab不同时结果为true)
a | b | a&b | a&&b | a或b | a或或b | !a | a^b |
---|---|---|---|---|---|---|---|
true | true | true | true | true | true | false | false |
true | false | false | false | true | true | false | true |
false | true | false | false | true | true | true | true |
false | false | false | false | false | false | true | false |
逻辑短路:
&&和||会有逻辑短路
即&&:如果第一个条件为false,第二个条件不会判断,最终结果为false
||:如果第一个条件为true,第二个条件不会判断,最终结果为true
优点: &&和||在运行有时只判断一个条件比&和|的效率高,所以在编程中常用&&和||
示例:
int a=2;
int b=3;
System.out.println(a==2);
System.out.println((a>3)&&(b++!=2));
System.out.println(b);
System.out.println((a>3)&(b++!=2));
System.out.println(b);
System.out.println((a>1)||(b++!=2));
System.out.println(b);
System.out.println((a>1)|(b++!=2));
System.out.println(b);
结果:
true
false
3
false
4
true
4
true
5
2.4) 赋值运算符
介绍:将运算后的值赋给指定的变量
基本赋值运算符: =
复合赋值运算符: +=,-=,/=,%=
a+=b等价于a=a+b(其余运算符用法可以类推)
- 赋值运算符特点
- 运算顺序从右往左
- 赋值运算符的左边只能是变量,右边可以是变量,表达式,常量值
- 复合赋值运算符会进行类型转换
如: byte a=1;
a+=3;等价于a=(byte)(a+3);
如果代码为a=a+3;由于整数(3)的数据类型是int所以程序会报错,使用复合赋值运算符会进行类型转换,程序就不会报错.
2.5) 三元运算符
条件表达式?表达式1:表达式2;
规则:
- 如果条件表达式为true,结果是表达式1;
- 如果条件表达式为false,结果是表达式2;
示例:
int a=2;
int b=3;
System.out.println(a>b?++a:b++);
System.out.println(b);
System.out.println(a);
System.out.println(a<b?++a:b++);
System.out.println(b);
System.out.println(a);
结果:
3
4
2
3
4
3
3) 控制结构
3.1 顺序控制
介绍:程序从上到下逐行执行,中间没有任何跳转和判断
3.2 分支控制
介绍:让程序有选择的执行
- 单分支
- 基本语法
if(条件表达式)
{ //如果()里个条件表达式结果为true则执行大括号内的语句. 否则直接跳过大括号
}
tips:如果{}中只有一条语句,可以省略{},但建议写上{}
示例:
int a=2;
int b=3;
if (a<b)
{
System.out.println("f");
System.out.println("k");
}
if(a>b)
{
System.out.println("c");
}
if(a<10)
System.out.println("x");
结果:
f
k
x
- 双分支
基本语法:
if(条件表达式)
{
代码1;
}
else//当表达式成立执行代码1否则执行代码2
{
代码2;
}
示例:
int day=1;
if (day==4)
{
System.out.println("crazy");
}
else {
System.out.println("没劲");
}
结果:
crazy
- 多分支
if(条件表达式1)
{
代码1;
}
else if(条件表达式2)
{
代码2;
}
…
else
{
代码n;//满足表达式1执行代码1,依次向下判断,都不满足执行代码n
}
示例
int a=5;
if (a==1)
{
System.out.println("go");
}
if (a==2)
{
System.out.println("stop");
}
else {
System.out.println("wait");
}
结果:
wait
- swicth
switch(表达式)
{
case 常量1;//表达式等于哪个常量就从哪个常量开始执行
代码1:
break;//遇到break退出swtich
case 常量2;
代码2:
break;
…
case 常量n;
代码n:
break;
default://所有常量都不等于表达式执行default
代码n+1;
break;
}
示例:
{case 1:;
System.out.println("go");
break;
case 2:
System.out.println("stop");
break;
case 3:
System.out.println("wait");
break;
}
结果:
go
- if和swich比较
- 判断的具体数值不多,且都符合byte,short,int,char,enum(枚举),String这6种类型,建议使用swtich
- 对区间判断,对结果为boolean类型判断,建议使用if
3.3 循环控制
- for循环
介绍:用以解决重复多次判断或输出或重复某段代码的问题
for (循环变量初始化;循环条件;变量迭代)
{ 语句(可以多条语句)//只有一条和if一样可以省略{}但建议加上
}
示例:
int a=2;
for(a=1;a<=4;a++)
{
System.out.println("rush");
}
结果
rush
rush
rush
rush
- for循环注意事项
循环条件返回的是一个布尔值表达式
for中的初始化和变量迭代可以写到其他地方,但分号不能省略[]如:for(;循环判断条件;)]
循环初始值初始化和变量迭代可以有多条,但是中间要用逗号隔开
- while循环
基本语法
while(循环条件)
{
语句;
循环变量迭代;
}
示例:
int a=1;
while(a<=6)
{
System.out.println("rush");
a++;
}
结果:
rush
rush
rush
rush
rush
rush
- do while循环
基本语法
循环变量初始化;
do{
语句;
循环变量迭代;
}while(循环条件);
示例:
int a=1;
do {
System.out.println("b");
a++;
}
while(a<=6);
do {
System.out.println("a");
a++;
}while (a>100);
结果:
b
b
b
b
b
b
a
4)数组
介绍:数组可以存放多个 同一类型 的数据.数组是 引用类型.即:数组就是一组数据
4.1) 数组的使用
一. 数组的定义
- 动态初始化1
数据类型 数组名[]=new 数据类型[数组大小]
(或者 数据类型 []数组名=new 数据类型[数组大小])
示例:
int []day=new int[7];//创建了一个存放int类型的数组,数组名为day,数组大小为7
int mouth[]=new int[12];
- 动态初始化2
先声明数组:数据类型 数组名[]; 或者 数据类型[] 数组名;int day[];或 int[] a;(这时day是空值null)
后创建数组:数组名=new 数据类型[数组大小];
day=new int[7];(这时分配给day内存空间,可以存放数据) - 静态初始化
数据类型 数组名[]={元素值,元素值…}
示例:
int num[]={2,3,5,7,11,13,17,19};
二. 数组的引用(访问)
数组名[下标] 比如:我要使用day数组的第4个数据 day[3]
(数组的下标从0到数组大小-1)
三. 数组使用细节
- 数组创建后,如果没有赋值,有默认值:
0: int,short,byte,long
0.0: float,double
\u0000: char
false: boolean
null: String - 数组下标从0开始
- 数组下标越界程序异常,比如int [] year=new int[4];有效下标为0到3;
- 数组属于引用类型,数组型数据是对象
4.2) 数组赋值机制
数组在默认情况下是引用传递,赋的是地址的值,赋值方式为引用赋值(即 被赋值的数组变得与赋值数组指向同一内存空间)
示例
int num1[]={1,3,5,7,8,10,12};
int num2[]=num1;//将num1的地址赋给num2
num2[0]=100;//将100赋给num2的第一个元素
for(int i=0;i<num1.length;i++)
{
System.out.println(num1[i]);
}
结果:
100
3
5
7
8
10
12
4.2.1) 数组拷贝
作用:使得拷贝后的数组不影响原数组
示例:
int num1[]={1,3,5,7,8,10,12};
int num2[]=new int[num1.length];//给num2开辟和num1同样大的空间
for(int i=0;i<num1.length;i++)//遍历num1 将num1的每个元素赋给num2的每个元素
{
num2[i]=num1[i];
}
num2[0]=99;
System.out.println("num2");
for(int i=0;i<num1.length;i++)
{
System.out.println(num2[i]);
}
System.out.println("num1");
for(int i=0;i<num1.length;i++)
{
System.out.println(num1[i]);
}
num2
99
3
5
7
8
10
12
num1
1
3
5
7
8
10
12
4.2.2) 数组翻转
方法一:
int num1[]={1,3,5,7,8,10,12};
int temp=0;
for(int i=0;i<num1.length/2;i++)//顺数和倒数位数相同的元素进行交换,一共交换数组长/2次
{
temp=num1[num1.length-i-1];
num1[num1.length-i-1]=num1[i];
num1[i]=temp;
}
for(int i=0;i<num1.length;i++)
{
System.out.println(num1[i]);
}
结果:
12
10
8
7
5
3
1
方法二:
int[] day={4,6,9,11};
int[] day2=new int[day.length];
for(int i=day.length-1;i>=0;i--)//逆序遍历数组day将数组day中的每个元素拷贝到数组二
{
day2[day2.length-i-1]=day[i];
System.out.println(day2[day2.length-i-1]);
}
day=day2;//将day2的地址赋给day1 day1原来空间中的值没有被引用 会被当做垃圾销毁
System.out.println("day数组");
for(int i=0;i<day.length;i++)//逆序遍历数组day将数组day中的每个元素拷贝到数组二
{
System.out.println(day[i]);
}
结果:
11
9
6
4
day数组
11
9
6
4
4.2.3) 数组扩容
要求:
- 增加元素6放在数组最后
- 可以通过输入y/n判断是否继续添加元素
import java.util.Scanner;
public class xiafan {
public static void main(String[] args){
Scanner myscanner =new Scanner(System.in);
int []num={1,2,3,4,5};
do {
int []num2=new int[num.length+1];//建立一个能比num数组多储存一个元素的数组num2
for(int i=0;i<num.length;i++)//遍历num数组将num的元素赋给对应的num2
{
num2[i]=num[i];
}
System.out.println("请输入你要添加的元素");
int addnum=myscanner.nextInt();
num2[num2.length-1]=addnum;
num=num2;//将num2的地址赋给num,num原来储存的元素会被当成垃圾销毁
for(int i=0;i<num.length;i++)
{
System.out.println(num[i]);
}
System.out.println("是否继续添加y/n");//询问客户是否继续添加
char key= myscanner.next().charAt(0);
if(key=='n'){
break;
}
}while(true);
System.out.println("你退出了程序");
结果:
请输入你要添加的元素
9//9为输入的数据
1
2
3
4
5
9
是否继续添加y/n
n//n为输入的数据
你退出了程序
数组缩减与扩容类似,方法如下:
import java.util.Scanner;
public class xiafan {
public static void main(String[] args){
Scanner myscanner =new Scanner(System.in);
int []num={1,2,3,4,5};
do {
int []num2=new int[num.length-1];//建立一个能比num数组少储存一个元素的数组num2
for(int i=0;i<num.length-1;i++)//遍历num数组将num的元素赋给对应的num2
{
num2[i]=num[i];
}
num=num2;//将num2的地址赋给num,num原来储存的元素会被当成垃圾销毁
for(int i=0;i<num.length;i++)
{
System.out.println(num[i]);
}
System.out.println("是否继续缩减y/n");//询问客户是否继续缩减
char key= myscanner.next().charAt(0);
if(key=='n'){
break;
}
else
{
if (num.length==1){
System.out.println("无法再次缩减");
break;
}
}
}while(true);
System.out.println("你退出了程序");
结果:
1
2
3
4
是否继续缩减y/n
y
1
2
3
是否继续缩减y/n
y
1
2
是否继续缩减y/n
y
1
是否继续缩减y/n
y
无法再次缩减
你退出了程序
4.2)排序
- 分类:
- 内部排序:
将所有需要处理的数据加载到内部存储器进行排序(包括交换式排序法,选择式排序法,插入式排序法) - 外部排序:
数据量过大,无法全部加载到内存中,需借助外部存储进行排序(包括合并排序法,直接合并排序法)
- 基本思想:从下标较大元素开始,依次比较相邻元素,若发现逆序则交换,使值较大的元素从前向后移(或向前),就像水底的气泡向上冒(又称冒泡排序)
- 示例:
int num[]={11,13,2,7,3,5};
int temp=0;
for(int i=1;i<num.length;i++){//第i次循环确定第i大的数
for(int n=0;n<num.length-1;n++){//每次循环判断是否交换的次数减一
if(num[n]>num[n+1]){
temp=num[n];
num[n]=num[n+1];
num[n+1]=temp;
}
}
}
for(int i=0;i<num.length;i++){
System.out.println(num[i]);
}
结果
2
3
5
7
11
13
4.3)查找
- 分类
- 顺序查找 SeqSearch.java
- 二分查找(二分法,学算法时再详细讲解)
示例:
String[] names={"汉堡王","金拱门","肯德基","华莱士"};
Scanner myScanner=new Scanner(System.in);
System.out.println("请输入餐厅");
String eat = myScanner.next();
int index=-1;
for(int i=0;i<names.length;i++){
if(eat.equals(names[i])){
System.out.println("这就是 "+eat);
System.out.println("下标为= "+i);
index =i;
break;
}
}
if(index==-1){
System.out.println("很抱歉,找不到 "+eat);
}
结果:
请输入餐厅
星巴克
很抱歉,找不到 星巴克
4.4) 二维数组
介绍:二维数组相当于每个元素都是一维数组的一维数组
- 初始化:
int a[][]=new int[4][3];//创建类似4*3的矩阵的数组 未赋值的值默认为0
a[2][1]=14;
int b[][] = {{0, 0, 0,5},//已知少量有限数据时的初始化
{0, 9, 8},//每行的一维数组可以有不同的元素个数
{0, 0, 5,0,77}
};
int c[][];//先定义
c=new int[2][7];//后赋值
for(int i=0;i<a.length;i++) {
for (int j = 0; j < a[i].length; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();
}
System.out.println("数组个数="+b.length);//length可以获得二维数组行数
System.out.println("第3行第3个数="+b[2][2]);//要取第i行第j个数要输入[i-1][i-1]
for(int i=0;i<b.length;i++){
for(int j=0;j<b[i].length;j++){
System.out.print(b[i][j]+" ");
}
System.out.println();
}
for(int i=0;i<c.length;i++){
for(int j=0;j<c[i].length;j++){
System.out.print(c[i][j]+" ");
}
System.out.println();
}
结果:
0 0 0
0 0 0
0 14 0
0 0 0
数组个数=3
第3行第3个数=5
0 0 0 5
0 9 8
0 0 5 0 77
0 0 0 0 0 0 0
0 0 0 0 0 0 0
- 动态初始化 列数不确定:
int a[][]=new int[3][];//创建了一个名为a的三行?列的二维数组
for(int i=0;i<a.length;i++)
{
a[i]=new int[i+1];//如果没有给一维数组new,那么a[i]=null
for(int n=0;n<a[i].length;n++){
a[i][n]=i+1;
}
}
for(int i=0;i<a.length;i++){
for(int n=0;n<a[i].length;n++) {
System.out.print(a[i][n]+" ");
}
System.out.println();
}
结果:
1
2 2
3 3 3
5) 初识类与对象
介绍:类(一种自定义的数据类型)可以存放多个的属性(数据)和行为(类似c语言中的函数) 可以通过类创建多个对象(具体的实例 如:666是int的一个对象)
例:
public class oop {
public static void main(String[] args) {
student student1 = new student();//student1为对象名 student1所指的空间(数据)为对象
student1.age=18;
student1.name="小明";
student1.gender="男";
student student2 = new student();
student2.age=19;
student2.name="李明";
student2.gender="女";
System.out.println("1号学生信息"+student1.age+" "+student1.name+" "+student1.gender);
System.out.println("2号学生信息"+student2.age+" "+student2.name+" "+student2.gender);
}
}
class student //定义了一个学生'类'(自定义的数据类型)
{//属性/成员变量/field(如果不定义有默认值,规则和数组一致)
int age;
String name;
String gender;
}
结果:
1号学生信息18 小明 男
2号学生信息19 李明 女
5.1) 对象分配机制
介绍:
- 栈:一般存放基本数据类型(局部变量)
- 堆:存放对象(student student1,数组等)
- 方法区:常量池(常量,比如字符串),类加载信息
例:
public class oop {
public static void main(String[] args) {
student student1 = new student();
//先在方法区加载student类属性信息和方法信息(属性和方法信息仅加载一次)
//然后new student会在堆里开一个空间 空间内数值为默认值
//student1 = new student()会使在栈里的student1指向刚刚在堆里的开的空间
student1.age=18;//将堆里的默认值换成18
student1.name="小明";//"小明"为字符串常量会被放在方法区常量池 堆里默认值会替换成常量池"小明"的地址
student1.gender="男";//同上
student student2 = student1;//把student1的地址复制给student2 student1和student2指向同一个空间
System.out.println(student2.name);
student1.name="李明";
System.out.println(student2.name);
}
}
class student //定义了一个学生'类'(自定义的数据类型)
{//属性/成员变量/field(如果不定义有默认值,规则和数组一致)
int age;
String name;
String gender;
}
结果:
小明
李明
5.2) 成员方法
介绍:
- 一个方法最多有一个return
- 返回类型包括基本类型和引用类型,return值与返回类型要一致
- 如果方法是void,可以没有return语句,或只写return
- 方法定义时的参数称为形参;调用时用的参数称为实参
- 同一个类中的方法可以直接调用其它方法
- 不同类的方法需要调用要先在需要调用的类中创建被调用类
- 基本数据类型传递的是值,形参改变不影响实参
- 引用类型传递的是地址,可以通过形参影响实参
- 传入数据为类时,属性和方法的改变不会影响主栈
例:
public class oop {
public static void main(String[] args) {
int answer,n=2,m=9,c;
//方法类似于C语言的函数 不在主函数内调用 不会输出
sum a1 =new sum();
judge a2=new judge();
a1.speak(n,m);//调用speak
answer=a1.get(n,m);//将返回的值赋给answer
System.out.println(answer);
if(a2.get2(n,m)){System.out.println("为奇数");}
else{System.out.println("为偶数");}
}
}
class sum { //public 表示方法是公开的
//void 表示方法无返回值
//speak 方法名
//() 为形参列表
//{}内为执行的代码
public void speak(int n,int m) {
System.out.println(n+"到"+m+"之和为");
}
//int 表示返回值为int类
public int get(int n, int m) {
int k=0;
for(int p=n;p<=m;p++)
{
k+=p;
}
return k;
}
}
class judge
{
public boolean get2(int n,int m) {
sum a = new sum();
int k=a.get(n,m);
return k%2!=0;
}
}
结果:
2到9之和为
44
为偶数
5.2.1) 方法递归调用
递归简介:同一个方法不断调用自己,每次调用传入不同变量,用来解决各种复杂问题(如汉诺塔)
例:
public class oop {
public static void main(String[] args) {
ta t=new ta();
t.move(3,'a','b','c');
}
}
class ta
{ public void move(int num,char a,char b,char c)
{
if(num==1){System.out.println(a+"->"+c);}
else{
move(num-1,a,c,b); //将num-1个盘移到b柱上
System.out.println(a+"->"+c);
move(num-1,b,a,c);//将num-1个盘移到c柱上
}
}
结果:
a->c
a->b
c->b
a->c
b->a
b->c
a->c
5.2.2) 方法重载
介绍:java允许同一类中,多个同名方法的存在,但要求形参列表不同(如System.out.println能输出不同数据类型)
例:
public class oop {
public static void main(String[] args) {
math math1=new math();
System.out.println(math1.sum(4,5));
System.out.println(math1.sum(4,7,9));
}
}
class math
{
public int sum (int n1,int n2)
{
return n1+n2;
}
public int sum (int n1,int n2,int n3)
{
return n1+n2+n3;
}
}
结果:
9
20
5.2.3) 可变参数
简介:部分(数据类型相同但数量不同)方法重载的合并
- 一个形参列表中只出现一个可变参数
- 可变参数必须放在形参列表中的最后
- 可变参数的实参可以为多个或0个
例:
public class oop {
public static void main(String[] args) {
math math1=new math();
int n[]={1,3,5,7,10};
System.out.println(math1.sum(2,3,5,7,11,13,17));
System.out.println(math1.sum1(2,3,5,7,11,13,17));
System.out.println(math1.sum(n));
}
}
class math {
public int sum(int... num) {
int ans=0;
for(int i=0;i<num.length;i++)
{
ans+=num[i];
}
return ans;
}
public int sum1(int c,int... num) {
int ans=0;
for(int i=0;i<num.length;i++)
{
ans+=num[i];
}
return ans;
}
}
结果:
58
56
26
5.2.4) 作用域
简介:
- 属性在方法内都能使用,被称为全局变量
- 属性之外的其它变量,作用域为定义它的代码块中,被称为局部变量
- 全局变量有默认值,可以直接使用.局部变量没有默认值,不能直接使用
- 属性和局部变量可以重名,访问时遵循就近原则
- 同一个作用域中,比如同一个成员方法中局部变量不能重名
- 属性可以被其它类使用(通过对象调用),局部变量
- 属性可以加修饰符,局部变量不行
例:
public class oop {
public static void main(String[] args) {
year nian=new year();
nian.mouth();
nian.week();
}
}
class year
{
int day=365;
int c;
public void mouth()
{
int day1=31;
System.out.println(day);
System.out.println(day1);
}
public void week()
{
System.out.println(day);
System.out.println(c);
//若在此处加上System.out.println(day1);的代码,程序报错
}
}
结果:
365
31
365
0
5.2.5) 构造方法/构造器
简介:类的一种特殊方法,主要作用是完成对新对象的初始化
- 没有返回值
- 方法名和类名相同
- 参数列表和成员方法规则相同
- 构造器的调用由系统完成
- 一个类可以有多个构造器(即构造器的重载)
- 如果没有定义构造方法,系统会自动给类生成一个无参构造方法.一旦定义了新的构造器,系统的无参构造器就被覆盖,若想使用需重定义
例:
public class oop {
public static void main(String[] args) {
year d1=new year(2,28);
System.out.println(d1.mouth+" "+d1.day);
}
}
class year
{ int mouth;
int day;
public year(int mouth1,int day1)
{
System.out.println("构造器被调用");
mouth=mouth1;
day=day1;
}
}
5.3) this关键字
简介:
- this可以用来访问本类属性 方法 构造器
- this 用于区分当前类的属性和局部变量
- 访问成员方法的语法:this.方法名(参数列表)
- 访问构造器语法(只能在构造器中使用):this(参数列表)
- this不能在类定义外使用
例:
public class oop {
public static void main(String[] args) {
person a1=new person();
System.out.println(a1.age+" "+a1.height);
a1.start(183,19);
System.out.println(a1.age+" "+a1.height);
a1.end();
System.out.println(a1.age+" "+a1.height);
}
}
class person {
int height;
int age;
public person() {//访问构造器语句必须放在构造器中第一句
this(180,18);//访问person(int height,int age)构造器
}
public person(int height,int age) {
this.height = height;//前面有this就固定为属性,无则取就近原则
this.age = age;
}
public void start(int height,int age) {
System.out.println("调用start");
this.height=height;
this.age=age;
}
public void end() {
this.start(0,0);//this.start()与start()类似但不同具体差别在继承体现
}
}
结果:
18 180
调用start
19 183
调用start
0 0
6 包
简介:
- 包 能区分相同名字的类
- 当类很多时 包 能便于管理
- 包 能控制访问范围
- 包 的本质:创建不同的文件夹保存类文件
- 包的命名规则: 只能包含数字,字母,下划线,小圆点 但不能用数字开头 不能含关键字或保留字
- 包的命名规范: com.公司名.项目名.业务模块名
- package 是声明当前类所在的包,需要放在class的最上面,一个类中最多一个package
- import指令 位置放在package下面
例:
package pet.num;
import pet.cat.black;//同名类只能引入一个 import pet.cat.black表示引入pet.cat包下black类
import pet.dog.*;//表示引入pet.dog 包下所有类
import java.util.Arrays;//java中自带的数组排序的类
public class num1 {
public static void main(String[] args) {
black shu=new black();
pet.dog.black dog1=new pet.dog.black();//不引入包名需写全
int []a={3,5,7,5,4,3,-1,11,7,13,0};
Arrays.sort(a);
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
}
}
结果:
-1 0 3 3 4 5 5 7 7 11 13
7) 访问修饰符
简介:
- 公开级别: public 对外公开
- 受保护级别: protected 对子类和同一个包中的类公开
- 默认级别: 没有修饰符 向同一个包的类公开
- 私有级别: private 只有类本身可以访问,不对外公开
- 修饰符可以用来修饰类中的属性,成员方法及类
- 只有默认的和public才能修饰类
访问级别 | 访问控制修饰符 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|---|
公开 | public | √ | √ | √ | √ |
受保护 | protected | √ | √ | √ | × |
默认 | 没有修饰符 | √ | √ | × | × |
私有 | private | √ | × | × | × |
8) 封装
简介:
- 封装就是把数据
属性
和数据的操作方法
封装在一起,数据被保护在内部,程序其他部分只有通过被授权的操作方法
,才能对数据进行操作 - 封装可以隐藏实现(方法)细节
- 封装可以对数据进行验证
- 封装的步骤:
- 将属性进行私有化(private)
- 提供一个公共的set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){
//加入数据验证
属性=参数名;
} - 提供一个公共的get方法,用于获取属性的值
public XX getXxx(){//权限判断
return xx;
}
例:
package com.fezh;
public class enan {
public static void main(String[] args) {
person a1= new person();
a1.setName("lihua");
a1.setAge(23);
a1.setSalary(3500);
System.out.println(a1.info());
System.out.println(a1.getSalary(1));
person jack = new person("jack", 666, 5800);
System.out.println(jack.info());
}
}
class person{
public person() {
}
public person(String name, int age, double salary) {
setSalary(salary);//如果直接用this.name=name就会绕过set无法验证数据
setAge(age);
setName(name);
}
public String name;
private int age;
private double salary;
public String getName() {
return name;
}
public int getAge() {
return age;
}
//set方法用来判断并对属性赋值
public void setAge(int age) {
if(age>=1&&age<=120){
this.age = age;}
else{
System.out.println("年龄范围在1-120,超过范围取18");
this.age=18;
}
}
public void setName(String name) {
if(name.length()>=2&&name.length()<=6){
this.name = name;}
else{
System.out.println(("名字长度在2-6"));
this.name="未登记";
}
}
public double getSalary(int a) {
if(a==123456)//给薪水查看上"密码"
{return salary;}
else {
System.out.println("密码错误");
return -1;
}
}
public void setSalary(double salary) {
this.salary = salary;
}
public String info(){
return "name "+name+" age "+age+" 薪水 "+salary;
}
}
结果:
name lihua age 23 薪水 3500.0
密码错误
-1.0
年龄范围在1-120,超过范围取18
name jack age 18 薪水 5800.0
9) 继承
简介:
- 基本语法:
class 子类 extends 父类{
} - 子类自动拥有父类定义的属性和方法
- 父类又叫超类/基类 子类又叫派生类
- 子类要调用父类私有属性和方法,需要通过父类提供公共的方法去访问
- 子类必须调用父类的构造器(系统默认会用
super
语法调用父类的无参构造器 即super() ) - 若父类没有提供无参构造器,必须在子类的构造器中去指定使用父类哪个构造器完成对父类的初始化工作
- super() 与 this() 都只能放在构造器第一行 因此两方法不能共存于一个构造器
- java的所有类都是Object的子类
- 子类最多只能继承一个父类
例:
父类:
package pet;
//dog和cat的父类
public class all {
//共有属性
public String name;
public int age;
private double sell;
public void setScore(double sell) {
this.sell = sell;}
public void info()
{
System.out.println("宠物名 "+name+" age "+age+" 价格 "+sell);
}
}
子类1:
package pet;
public class cat extends all {
public void circus(){
System.out.println("小猫"+name+"正在摸鱼");
}
}
子类2:
package pet;
public class dog extends all {
public void circus(){
System.out.println("小狗"+name+"正在祈祷");
}
}
测试:
package pet;
public class test {
public static void main(String[] args) {
dog dog1 = new dog();
dog1.name="旺财";
dog1.age=3;
dog1.setScore(348);
dog1.circus();
dog1.info();
System.out.println("--------");
cat cat1 =new cat();
cat1.name="大白";
cat1.age=5;
cat1.setScore(568);
cat1.circus();
cat1.info();
}
}
结果:
小狗旺财正在祈祷
宠物名 旺财 age 3 价格 348.0
--------
小猫大白正在摸鱼
宠物名 大白 age 5 价格 568.0
10) supper关键字
简介:
- super代表父类的引用,用于访问父类(包括父类的父类的…直到object)的属性,方法,构造器 不能访问private属性/方法
- 使用super访问属性,方法时会跳过本类(用this访问时会优先访问本类,若本类没有再访问父类)
- 基本语法:
访问父类属性:super.属性名
访问父类方法super.方法名(参数列表)
访问父类构造器:super(参数列表)
11) 方法重写/覆盖
简介:
- 子类的一个方法与父类某个方法的方法名称,参数一样,且子类方法的返回类型与父类方法返回类型一样或是其子类(如父类返回类型是Object 子类返回类型是String),我们就说这个子类的这个方法覆盖了父类的方法
- 子类方法不能缩小父类方法的访问权限(按照public>protected>默认>private的规则 子类只能扩大或相等 不能缩小)
例:
父类:
package fuf;
public class fufu {
private String name;
private int age;
public fufu(String name,int age)
{
this.name =name;
this.age=age;
}
public String talk()
{
return "my name is "+name+"今年"+age+"岁";
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
子类:
package fuf;
public class son1 extends fufu{
private int id;
private double score;
public son1(String name, int age, int id, double score) {
super(name, age);//访问父类构造器
this.id = id;
this.score = score;
}
public String talk(){
return super.talk()+" id="+id+" score="+score;
}//对父类talk方法的重写
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
主类:
package fuf;
public class mainn {
public static void main(String[] args) {
fufu Lihua=new fufu("Lihua",10);
System.out.println(Lihua.talk());
son1 xiaoming = new son1("xiaoming", 20, 12138, 61);
System.out.println(xiaoming.talk());
}
}
结果:
my name is Lihua今年10岁
my name is xiaoming今年20岁 id=12138 score=61.0
12) 多态
12.1) 初识多态
多态的体现:
- 方法的多态:
重写和重载体现多态 - 对象的多态
- 一个对象的编译类型(定义时 = 号左边)和运行类型(定义时 = 号右边)可以不一致
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型可以改变
多态的本质:父类的引用指向了子类对象
多态的向上转型
- 语法: 父类类型 引用名=new 子类类型
- 注意事项:
- 可以调用父类中所有成员
- 不能调用子类中特有成员(即没有重写父类方法的子类方法)
多态的向下转型
- 语法: 子类类型 引用名=(子类类型)父类对象
- 只能强制转移父类的引用,不能强制转移父类类型
- 父类的引用必须指向当前目标类型的对象
- 向下转型后可以调用子类类型中所有成员
例:
package 多态;
public class justdo {
public static void main(String[] args) {//sun和moon都为god的子类且praise重构
god god1 =new god();
god1.praise();
god1 =new moon();// god 为 god1 的编译类型 moon 为 god1 的运行类型
god1.praise();
god1 =new sun();//运行类型变更为 sun
god1.praise();
god god0=god1;//向上转型
//sun和moon含独有方法eng不能直接引用
god god2 =new moon();
moon god3 =(moon) god2;//只能强制转移父类的引用,不能强制转移父类类型
god3.eng();//向下转型后即可调用子类独有方法
sun god4 =(sun) god1;//父类的引用必须指向当前目标类型的对象 例如要god4转型成sun god1的运行类型要是sun
god4.eng();//属性看编译类型 不看运行类型
System.out.println(god1 instanceof god);//引用名a instanceof 类型b 可以判断是否为a是否为b类型或为b类型的子类
System.out.println(god1 instanceof sun);
System.out.println(god1 instanceof moon);
}
}
结果:
赞美神!
赞美月亮!
赞美太阳!
moon!
sun!
true
true
false
12.2) 动态绑定机制
- 当调用对象方法时,该方法会和该对象的内存地址(即运行类型)绑定
- 当调用对象属性时,没有动态绑定机制,哪里声明哪里使用
例:
package fuf;
public class mainn {
public static void main(String[] args) {
class xm
{
public int sc=60;
public int getSc() {
return sc;
}
public int up()
{
return getSc()+10;
}
public int down()
{
return sc-10;
}
}
class lihua extends xm
{
public int sc=59;
public int getSc() {
return sc;
}
//public int up()
//{
// return getSc()+10;
//}
//public int down()
//{
// return sc-10;
//}
}
xm stu=new lihua();
System.out.println(stu.up());//遵循动态绑定机制调用lihua.getSc
System.out.println(stu.down());//直接引用xm的sc
}
}
结果
69
50
12.3) 多态数组
简介:数组的定义类型为父类类型,里面保存的元素类型为子类类型
语法:父类类型[] 引用名=new 父类类型[i] (i为数组长度)
调出子类特有方法:((子类类型)引用名[i]).方法名()
(即向下转型 可以用instanceof判断是否为对应子类以防报错 )
13) static关键字
- 修饰属性时,使其成为静态变量.静态变量可以直接用类名访问,能被类中的所有实例共享
- 修饰方法时,使其成为静态方法,静态方法可以在类中的非静态方法直接调用.但是静态方法只能调用静态方法不能调用非静态方法(静态方法优先加载)
- 修饰匿名代码块时, 代码块中的代码在其余代码运行前优先运行,且仅运行一次.
- 修饰导入类时,可以在后面加上 .方法名 这样就可以直接用方法名调用静态方法,而不必用 类名.方法名 的方式来调用
14) 抽象
14.1) 抽象类
- 抽象类、抽象方法用abstract修饰. 抽象方法仅有方法名字,没有方法实现 抽象类的所有方法必须由基础它的子类实现(除非子类也是抽象类)
- 抽象类不能new,仅能靠子类实现它
- 抽象类中可以写普通的方法
- 抽象方法必须写在抽象类中
- 抽象类有构造器,因为抽象类是可以被继承的,所以其子类在实例化时需要调用父类的构造器
- 抽象类用extends继承
14.2) 接口
- 接口只有规范,自己无法写方法,接口可以被用于多线程.
- 用interface定义类使其成为接口,接口中的所有定义都是抽象的(若不写默认为抽象)
- 接口都需要实现类(因为接口内仅有定义没有实现),接口的实现类要在类名后加上 implements 接口名 实现接口的类要重写接口中的所有方法
- 接口中定义的属性默认为常量(不常用)