JJJJJavaaaaaaaa啊啊啊啊
文章目录
Chapter1
-
JDK = JRE + java开发工具, JRE = JVM +核心类库
-
运行的本质就是把.class 装载到JVM虚拟机中执行
-
对于类和方法的注释 要以javadoc 的方式来写
/** */
-
dos命令:
dir查看里面的文件
,cd切换目录
,tree查看所有子目录
,cls清屏
,md创建文件
,rd删除目录
,del删除文件
,move 剪切
,copy 拷贝
Chapter2 变量
-
变量相当于内存中一个数据存储空间的表示——变量的声明,赋值,使用
-
+
两边有一边是字符串,那么就做拼接运算。如果两边都是数值就做求和运算。 -
Java数据类型:
1️⃣ 基本数据类型:数值型:整数类型——存放整数:byte[1] short[2] int[4] long[8]
浮点类型——存放小数:float[4] double[8]
字符型——存放单个字符:char[2]
布尔型——存放true、false:boolean[1]
2️⃣ 引用数据类型:类(class),接口(interface),数组([ ]) -
java自动类型转化(在进行赋值或者运算时,精度小的 自动提升至 精度大的):
-
char → int → long → float → double
-
byte → short → int → long → float → double
-
boolean类型不参与类型的自动转化
-
有多种数据类型一起运算的时候,系统会把他们都转化到精度最高的类型;
-
(byte, short) 和 char 之间不会相互自动转化;
-
byte, short 和 char 三者可以计算,也就是说只有有这三个任何一个在计算的时候,都会会首先自动转化为int类型;
-
float d1 = 2 + 2.2; // 错误,因为2是默认的int,2.2是默认的double,转化为double计算后不能赋给float int d2 = 1.1; // 错误,double不能转int byte d3 = 10; int n2 = 1; byte b2 = n2; // 错误:d3是byte一个字节,n2是int四个字节,于是不能把n2赋给b2 byte m1 = 10; char m2 = m1; short m3 = m1; // 错误: (byte, short) 和 char 之间不会相互自动转化 byte q1 = 10; byte q2 = 10; byte q3 = q1 + q2; // 错误:byte参加运算,会自动转化为int类型,所以不正确
-
-
基本数据类型转化为字符串String ——
+ ""
int n1 = 100; float f1 = 1.1F; double d1 = 4.5; boolean b1 = true; String s1 = n1 + ""; String s2 = f1 + ""; String s3 = d1 + ""; String s4 = b1 + "";
字符串String转化为对应的基本数据类型——通过基本类型的包装类调用parseXX方法
// 使用基本数据类型对应的包装类的相应方法 得到基本数据类型 String s5 = "123"; int num1 = Integer.parseInt(s5); double num2 = Double.parseDouble(s5); float num3 = Float.parseFloat(s5); long num4 = Long.parseLong(s5); short num5 = Short.parseShort(s5); byte num6 = Byte.parseByte(s5); boolean num7 = Boolean.parseBoolean("char"); // 取出来s5字符串的第一个字符 System.out.println(s5.charAt(0));
-
java的整型常量默认为int类型,声明long类型常量后需加
L或者l
java的浮点型常量默认为double类型,声明float类型常量后需加F或者f
-
浮点数 = 符号位+指数位+尾数位
-
char的本质是一个整数,可以参与运算,在输出的时候是unicode码对应的字符
char c1 = 'a'
输出【a】
char c3 = 97
输出【a】
字符型存储到计算机的时候,‘a’ >> 码值97 >> 二进制1100001 >> 存储
字符型从计算机读取的时候,二进制 >> 97 >> ‘a’ >> 显示
char m1 = 'a';
char m2 = 'z';
System.out.println(m1 + m2); //char类型本质是整数运算 >>> 输出219
-
ASCII码表:使用1个字节,有128个字符的编码(没用完);
Unicode码: 使用了2个字节,英文和汉字都占2个字节;
UTF-8:是最广泛使用的一种Unicode实现方式,变长编码,且字母1个字节,汉字3个字节。 -
布尔类型:
boolean
,但是java中不可以用0或者非零表示true和false -
pirntln、print的运算规则:在遇到第一个字符串之前,所有的数遇到加号即相加。当遇到任意字符后,加号就变成了字符串的拼接。
Chapter3 运算符
-
在java中
取模 %
的本质:a % b = a - a / b * b
,如果a是小数则:a % b = a - (int)a / b * b
-
++的独立使用
:i++ <=> ++i <=> i = i+1
++作为表达式使用
:[1] 前++:++i先自增再操作 ; [2] 后++:i++先操作后自增int j = 8; int k = ++j; // 等价于 j=j+1, k=j int m = j++; // 等价于 m=j, j=j+1
int i = 1; // i->1 i = i++; //(1)temp=i (2)i++ (3)i=temp 所以最后i=1
int i = 1; // i->1 i = ++i; //(1)i++ (2)temp=i (3)i=temp 所以最后i=2
-
关系运算符: == != < > <= >= instanceof 关系表达式的运算的结果是boolean型
-
逻辑运算符:短路与&& 短路或|| 取反! 逻辑与& 逻辑或| 逻辑异或^
短路与&&
:如果第一个为false,则后面的条件不会判断,最终直接为false【效率高】逻辑与&
:如果第一个为false,后面的条件仍然会执行和判断短路或||
:如果第一个为true,则后面的条件不会判断,最终直接为true【效率高】逻辑或|
:如果第一个为true,后面的条件仍然会执行和判断
-
赋值运算符:复合赋值运算符底层会进行类型转化
byte b = 2; b += 2; // √ 等价于b = (byte)(b+2) b = b + 2 // × b+2会变成int类型,int类型无法赋值给byte类型
-
三元运算符:
条件表达式?表达式1:表达式2;
——如果条件表达式为真,则运算后结果为表达式1,否则为2。//寻找两数之间最大数 int m = 59; int n = 2; int max = m > n ? m : n; System.out.println(max);
-
标识符命名规则:由字母,$,_,数字组成;不以数字开头;不可以是关键字保留字,区分大小写,不含空格。
-
标识符命名规范:驼峰法xxxYyyZz,常量名:XXX_YYY_ZZZ,类名接口名:XxxYyyZzz
-
键盘输入:
import java.util.Scanner; // 把java.util包下的Scanner类导入 public class Input{ public static void main(String[] args){ // Scanner 类表示简单的文本扫描器,在java.util 包 // 1.引入 Scanner类所在的包 // 2.创建Scanner对象 new创建一个对象 Scanner myScanner = new Scanner(System.in); //3. 接受用户的输入,使用相关的方法 System.out.println("请输入名字:"); String name = myScanner.next();
// 几种格式的键盘输入读取 String name = myScanner.next(); int a = myScanner.nextInt(); double b = myScanner.nextDouble(); char c = myScanner.next().charAt(0);
-
位运算
- 对于有符号数来讲,最高位0表示正数,1表示负数。
- 正数的原码、反码、补码都一样。
- 负数的反码:原码的符号位不变,其他位按位取反。
- 负数的补码:其反码+1,同理负数的反码 = 负数的补码 -1。
- 0的反码补码都是0。
- java没有无符号数,所有数都有符号。
- 计算机运算的时候,都是以补码的方式运算的。看运算结果的时候,看的是原码。
-
位运算符:
按位与&
,按位或|
,按位异或^
,按位取反~
,算数左移<<
:符号位不变,低位补0;算数右移>>
:符号位不变,低位溢出,并用符号位补溢出的高位;无符号右移>>>
:低位溢出,高位补0。
Chapter4 程序控制结构
1)if-else
if(age > 18){
System.out.println("1");
}else if{
System.out.println("2");
}else{
System.out.println("3");
}
// 如果没有else 有可能程序就一个入口都没有哦
2)switch
// 表达式的数据类型,应该和case后面的常量类型一致
// 或者可以自动转化成可以相互比较的类型
// 表达式的返回值必须是:byte short int char enum[枚举] String!!!
switch(表达式){
case 【1】 :
System.out.println("今天周一");
break; //如果不加break就会继续向后执行
case 【2】 :
System.out.println("今天周二");
break;
case 【3】 :
System.out.println("今天周三");
break;
default:
System.out.println("未知");
}
// 利用穿透
switch(score){
case 3:
case 4:
case 5:
System.out.println("春天");
break;
default:
System.out.println("春天");
}
- 表达式的数据类型应该和case后面的常量类型一致, 或者可以自动转化成可以相互比较的类型;
- 表达式的返回值必须是:byte, short,int, char, enum[枚举], String;
- case子句中的值必须是常量或者是常量表达式(比如’a’,1,‘a’+1…),而不能是变量;
- default:子句是可选的,没有匹配的case就执行default,但是没有default也可以;
- break语句:作用就是跳出switch语句,如果没有break程序就顺序执行其他case;
3)for循环
for(①循环变量初始化;②循环条件;④循环变量迭代){
③循环操作(可以是多条语句)
}
// 写法一
for(int i = 1; i < 10; i++){
System.out.println("a");
}
// 写法二[分号不能少]
int i = 1; //循环变量的初始化
for( ; i < 10; ){
System.out.println("a");
i++; //循环变量迭代
}
// 无限循环
for(;;){
}
4)while循环
循环变量的初始化;
while(循环条件){
循环体(语句);
循环变量迭代;
}
无限循环(用break退出):
while(true){
if(XXX){break;}
}
5)do - while循环
先执行在判断,至少会执行一次
循环变量的初始化;
do{
循环体(语句);
循环变量迭代;
}while(循环条件); //记得分号;
6)break
- 用于终止某个语句块的执行;
- break语句块出现在多层嵌套语句块中的时候,可以通过标签指明要终止的是哪一层的语句块,
break 标签名
。如果没有label,则break默认退出最近的循环体。
7)continue
- 用于结束本次循环,继续执行下一次循环;
- continue语句块出现在多层嵌套语句块中的时候,可以通过标签指明要跳过的是哪一层的循环,
continue 标签名(label)
。如果没有label,则continue默认退出最近的循环体。
8)return 跳转控制语句
- 用于跳出所在的方法,若用在main方法,则退出程序。
Chapter5
1)数组
可以存放多个同一类型的数据,数组属于引用类型这一数据类型。
-
注意事项
-
数组中的元素可以是任何数据类型,但是不能混用。
-
数组创建后,如果没有赋值,则默认值为:int 0, short 0, long 0, byte 0, float 0.0, double 0.0, char \u0000, boolean false, String null。
-
数组的下标必须在指定范围内使用,否则运行时报越界异常。
-
数组是引用类型,所以数组型数据是对象(object)。
-
数组赋的值是【地址】,赋值的方式是引用传递。基本数据类型赋值是值传递,拷贝值。
// 把arr1赋给arr2,改变arr2,arr1也会改变【数组赋值是引用赋值,不是值传递】 int arr1[] = {1,2,3}; int arr2[] = arr1;
arr1,arr2中存放的是地址,对应堆的地址里面有一定个数的空间。
-
若原来的数据空间没有变量引用,就会被JVM当做垃圾回收。
-
-
数组的定义:
//第一种动态分配方式 int array[] = new int[5]; // 创建一个数组,名字为a,存放5个int //第二种动态分配方式 int array[]; // 先声明数组,此时a是null array = new int[5]; // 分配内存空间,可以存放数据 //静态初始化 int array[] = {1, 2, 3, 4, 5}; // 创建并初始化一个数组
-
数组的访问:
array[i]
-
数组的长度:
array.length
-
数组拷贝(要求两个数组的空间是独立的,因为数组形如arr1 = arr2的赋值的方式是引用传递【传递地址】)
int array1[] = {1,2,4,5}; // 开辟一个新的空间 这个空间的地址肯定和array1不一样,这个空间里的每一个元素为初始化的0 int array2[] = new int[array1.length]; // 遍历array1 拷贝每一个值到array2 for(int i = 0; i < array1.length; i++){ array2[i] = array1[i]; }
-
数组添加元素(本质是数组的扩容)
-
二维数组
int array[][] = new int[2][3]; // 动态初始化方式1 int array[][]; array = new int[2][3]; // 动态初始化方式2 int array[][] = {{0,1,2,3},{4,5,6,7},{8,9,9,9},{6,6,6,6}}; // 静态初始化 int array[][] = {{1,2,3},{0},{1,6}}; // 静态初始化 二维数组中的一维数组个数(即行数):array.length 每个一维数组的长度(即列数):array[i].length 访问每一个元素 array[i][j]
二维数组 栈指向堆中的一个空间,这个空间里的元素是一维数组的地址,指向另一个空间,这个空间才存放元素
动态初始化:列数不确定的情况:
打印: 1 2 2 3 3 3 4 4 4 4 // 创还二维数组,包含4个一维数组,但是每个一维数组还没有开数据空间!!!! int array[][] = new int[4][]; for(int i =0; i < array.length; i++){ // ☆遍历二维数组array的每个一维数组,给每个一维数组开空间!!这里如果没给一维数组new,那么array[i]就是null array[i] = new int[i+1]; //遍历一维数组,并给一维数组的每个元素赋值 for(int j =0; j < array[i].length; j++){ array[i][j] = i+1; } } // 遍历输出 for(int i = 0; i < array.length; i++){ for(int j = 0; j < array[i].length; j++){ System.out.print(array[i][j]); }System.out.println(""); }
其他的一些小tips:
int[] x, y[]; // 声明一个一维数组x,一个二维数组y int array[] = new int[]{1,2,4}; // 这种写法也可以哦,由编译器自动判断空间多大
2)排序
2.1 冒泡排序
通过对待排序的序列,依次两两比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前向后移。
从小到大排序 》》》大的后移
从大到小排序 》》》 小的后移
// 从小到大排序
// 24 69 80 57 13
// 24 69 57 13 80
// 24 57 13 69 80
// 24 13 57 69 80
int array[] = {24,69,80,57,13};
int temp = 0;
for(int i = 0; i < array.length - 1; i++){
for(int j = 0; j < array.length - i - 1; j++){
if(array[j] > array[j+1]){ // 从小到大排序就是> ,从大到小排序空间就是<,so easy
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
2.2 查找
2.2.1 顺序查找
for(int i = 0; i < array.length; i++){
if(array[i] == num){
System.out.println(i)
}
}
2.2.2 二分查找
Chapter6 OOP类和对象(class and object)
-
int是一种数据类型,类是自定义的数据类型,可以通过类创建多个对象(也就是类的实例化)。
-
类是抽象的,概念的,代表一类事物,是数据类型;
-
对象是具体的,实际的,代表一个具体的实物,是实例;
-
类是对象的模板,对象是类的一个个体,对应一个实例。
-
实际操作
public class object01{ public static void main(String[] args){ // 实例化一只猫(创建一只猫对象) // new Cat() :创建一只猫对象 // Cat cat1 = new Cat() :把创建好的猫赋给cat1 Cat cat1 = new Cat(); cat.name = "小白"; cat.age = 12; cat.color = "白色"; // 创建第二只猫,并赋给cat2 Cat cat2 = new Cat(); cat.name = "小蓝"; cat.age = 11; cat.color = "黑色"; // 访问对象的属性 System.out.println("第1只猫的信息" + cat1.name + " " + cat1.age + " " + cat1.color); System.out.println("第2只猫的信息" + cat2.name + " " + cat2.age + " " + cat2.color); } } // 定义一个猫类Cat -> 自定义的数据类型 class Cat{ //属性 String name; int age; String color; }
-
🔴对象的属性在内存中的存在形式:
如果属性的类型是字符串,而字符串是引用类型,堆中对应的空间里就存放指向方法区常量池的地址,如果是基本数据类型就直接存在堆中。cat只是指向了对象的空间,叫做对象名(或者是对象引用),new Cat()创建的对象空间才是真正的对象,创建后里面默认值为null ,0, null,后三条语句"小白",12,”白色“才会根据数据类型分别赋值或者存地址进去。
6.1 创建对象
// 方法1 先声明再创建
Cat mycat;
mycat = new Cat();
// 方法2 直接创建
Cat mycat = new Cat();
6.2 类与对象的内存分配机制
- 栈:一般存放基本数据类型(局部变量)
- 堆:存放对象(就包括之前的Cat mycat ,数组)
- 方法区:常量池(常量,比如字符串),类加载信息
6.3 属性(又叫成员变量 field)
6.3.1 属性的定义
属性是类的一个组成部分,一般是基本数据类型,也可以是引用类型(对象,数组)
-
属性的定义:
访问修饰符 属性类型 属性名
-
访问修饰符
——控制属性的访问范围:包括public
,proctected
,默认
,private
-
// 【属性的定义】 class Person{ int age; String name;}
-
-
属性的定义类型可以为任意类型,包含基本类型和引用类型;
-
属性如果不赋值有默认值,规则和数组一致。
- int 0, short 0, long 0, byte 0, float 0.0, double 0.0, char \u0000, boolean false, String null。
6.3.2 访问属性
// 对象名.属性名
mycat.color;
mycat.age;
6.4 成员方法的创建和调用(为了让类除了属性还有一些行为)
6.4.1 成员方法的定义
// 【成员方法的定义】
访问修饰符(有四种) 返回数据的类型 方法名(形参列表) {//方法体
语句;
return...;
}
6.4.2 成员方法举例
public class method{
public static void main(String[] args){
//【方法的调用】 创建一个对象,然后调用方法
Person myperson = new Person(); //创建一个对象
myperson.speak(); //调用speak方法
int res = myperson.sum(2,3); //调用sum方法 传参给num1,num2,
System.out.println(res); //将方法sum返回的值赋给变量res
}
}
class Person{
int age; // 类的属性
System name; // 类的属性
// 【创建成员方法1】 添加speak成员方法 输出“我是一个好人”
// public :表示方法是公开的
// void :表示方法没有返回值
// speak() :speak是方法名,( )是形参列表
// {} :方法体,可以写我们要执行的代码
public void speak(){
System.out.println("我是一个好人");
}
// 【创建成员方法2】 返回两个值的和
// int num1,int num2: 形参列表,表示当前有2个int类型的形参,可以接受用户的输入
// int 表示return返回值为int类型
public int sum(int num1, int num2){
int res = num1 + num2;
return res;
}
}
【创建成员方法3——有多个返回值】
public class method03{
public static void main(String[] args){
// 有两个返回值 返回一个和 一个差
Work mywork = new Work(); //新建一个对象
int arr[] = mywork.output(2,3);
//输入一个2,一个3,接受一个返回值,返回值是一个数组,里面有俩值
System.out.println("和为:" + arr[0]);
System.out.println("差为:" + arr[1]);
}
}
class Work{
public int[] output(int num1, int num2){ //返回值是一个数组,数组里就可以包括多个返回值
int array[] = new int[2]; // 创建一个新数组
array[0] = num1 + num2;
array[1] = num1 - num2;
return array;
}
}
6.4.3 成员方法注意细则:
🔴 ! 成员方法的调用机制0203_韩顺平Java_方法调用机制_哔哩哔哩_bilibili
**1.**当程序执行到方法的时候,就会开辟一个独立的空间(栈空间);
**2.**当一个方法执行完毕,或者执行到return语句的时候,就会返回,返回到调用方法的地方。
**3.**返回后继续执行下面的代码。
**4.**当main方法(栈)执行完毕后,整个程序退出
返回数据类型
1.一个方法最多有一个返回值 [若要返回多个结果——>返回数组 ] ;
2.返回类型可以为任意类型,包含基本类型或引用类型(数组,对象) ;
3.如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值,而且要求返回值类型必须和 return 的 值类型一致或兼容;
4.如果方法是 void,则方法体中可以没有 return 语句,或者 只写 return ;
形参列表
1.一个方法可以有0个参数,也可以有多个参数,中间用逗号隔开;
2.参数类型可以为任意类型,包含基本类型和引用类型;
3.调用带参数的方法时,要对应着参数列表传入相同类型,或者兼容类型的参数;
4.方法定义时的参数为形参,方法调用时传入的参数为实参,实参和形参的类型要一致或者兼容,个数和顺序必须要一致。
方法体
1.方法名遵循驼峰命名法,见名知义;
2.方法体里面写完成功能的具体语句
3.方法体里面不能再定义方法(方法不能嵌套定义)
方法调用的细节说明
1.同一个类中的方法调用——直接调用即可,不需要创建对象
2.跨类中的方法 A类调用B类的方法——需要创建B类对象,再通过对象名调用方法
3.跨类方法的调用和方法的访问修饰符有关【暂不涉及】
6.4.4 成员方法的传参机制
1.基本数据类型传递的是值(值拷贝),所以形参的任何改变不影响实参。
2.引用数据类型传递的是地址,所以可以通过形参影响实参。(包括数组 对象)0211_韩顺平Java_方法传参机制2_哔哩哔哩_bilibili
6.4.5 克隆对象
public class MethodExercise03{
public static void main(String[] args){
Person myperson = new Person();
myperson.name = "lmx";
myperson.age = 123;
MyTools mytool = new MyTools();
Person mypersonnew = mytool.copyPerson(myperson);
// myperson和mypersonnew 都是Person对象,但是是两个独立的对象,属性相同
// 可以通过输出对象的hashCode来看对象是否是一样的.
System.out.println(mypersonnew == myperson);
}
}
class Person{
int age;
String name;
}
class MyTools{
public Person copyPerson(Person p){
//编写一个方法copyPerson,可以复制一个Person对象,返回复制的对象。
//注意要求得到新对象和原来的对象是两个独立的对象,只是他们的属性相同
//编写方法的思路
//1)方法的返回类型 Person
//2)方法的名字 copyPerson
//3)方法的形参 (Person p)
//4)方法体,创建一个新对象,并复制属性,返回即可
Person pnew = new Person();
pnew.age = p.age;
pnew.name = p.name;
return pnew;
}
}
6.4.6 方法递归调用(方法自己调用自己)
[1] 执行一个方法时,就创建一个新的受保护的独立空间(栈空间);
[2] 方法的局部变量是独立的,不会相互影响,比如n变量;
[3] 如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据;
[4] 递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError,死龟了;
[5] 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
八皇后?
6.4.8 方法重载 OverLoad
java允许同一个类中,多个同名方法存在,但要求形参列表不一致。
注意事项:
(1)方法名必须相同;
(2)形参列表必须不相同(形参类型,个数,顺序必须至少有一个不同,和参数名无关);
(3)对返回类型无要求
举例
class MyCalculator{
public int calculate(int n1, int n2){
return n1+n2;
}
public double calculate(int n1, double n2){
return n1+n2;
}
public double calculate(double n1, int n2){
System.out.println("被调用");
return n1+n2;
}
public int calculate(int n1, int n2, int n3){
return n1+n2+n3;
}
}
6.5 可变参数
java允许将一个类中多个同名同功能但是参数个数不同的方法 封装成一个方法
6.5.1 可变参数基本语法
访问修饰符 返回类型 方法名(数据类型...形参名){
方法体
}
int... : 表示接收的是可变参数,类型是int,即可以接受多个int
使用可变参数的时候可以当做数组来使用,比如可以用 形参名.length 返回传入的形参个数,求和等等
举例:
// 可变参数 可以计算两个数 三个数 四个数...的和
public class VarParameter01{
public static void main(String[] args){
HspMethod m = new HspMethod();
System.out.println(m.sum(1,2,3,4));
}
}
class HspMethod{
public int sum(int...nums){ // 功能相同 参数个数不同 -> 使用可变参数优化 本质是数组
int sum =0;
for(int i = 0; i < nums.length; i++){
sum += nums[i];
}return sum;
}
}
6.5.2 可变参数的注意事项
- 可变参数的实参可以为0个或者任意多个;
- 可变参数的实参可以直接为数组;
- 可变参数的本质就是数组;
- 可变参数可以和普通类型的参数一起放在形参列表,但是必须保证可变参数在最后
eg:public int Sum(int a, double b, int...c);
- 一个形参列表中只能有一个可变参数!
6.6 作用域
- 在java编程中,主要的变量就是属性(成员变量)和局部变量。
- 我们说的局部变量一般是指在成员方法中定义的变量。
- java中作用域的分类:
- 全局变量:也就是属性,作用域为整个类体,可以被本类使用,也可以通过对象调用被其他类调用。
- 局部变量:也就是除了属性之外的其他变量,局部变量的作用域为定义它的代码块中!只能在本类中对应的方法中使用。
- 全局变量(属性)可以不赋值,直接使用,因为有默认值。局部变量必须赋值后才能使用,因为没有默认值。
- 局部变量和全局变量(属性)可以重名,访问时就近原则。
- 在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名。
- 全局变量(属性)的生命周期长,伴随对象的创建而创建,伴随对象的销毁而销毁;
局部变量生命周期短,伴随着他的代码块的执行而创建,伴随着代码块的销毁而销毁(执行方法时 该方法的局部变量被创建,方法结束后被销毁)。 - 全局变量(属性)可以加修饰符:
public
,proctected
,默认
,private
;
局部变量 不可以加修饰符。
6.7 构造方法/构造器(constructor)
是类的一种特殊方法,在构造对象的时候,完成对新对象的初始化。
6.7.1 构造器基本语法
修饰符 方法名(形参列表){
方法体
}
注意事项:
- 构造器的修饰符可以默认;
- 🅰️构造器没有返回值;
- 🅰️构造器名和类名字必须一样;
- 参数列表和成员方法一样的规则;
- 🅰️在创建对象的时候,系统会自动调用该类的构造器 去完成对象的初始化,并不是创建对象。
6.7.2 构造器举例
public class constructor01{
public static void main(String[] args){
//创建人类对象的时候直接指定他的年龄和姓名
//当new一个对象的时候,通过构造器直接指定名字和年龄
Human my = new Human(90, "lmx");
System.out.println(my.age);
System.out.println(my.name);
}
}
class Human{
// 定义属性
int age;
String name;
// 【构造器】:在创建对象的时候,系统会自动调用该类的构造器 去完成对象属性的初始化
// 构造器的名字和Human一样
// 构造器没有返回值
// (String pName, int pAge)是构造器的形参列表
public Human( int pAge, String pName){
name = pName;
age = pAge;
}
}
6.7.3 构造器注意事项
-
构造器本身也算是一个方法,和方法重载一样,一个类可以定义多个不同的构造器,即构造器重载;
-
如果没有定义构造器,则系统会自动给类生成一个默认无参构造器(默认构造器);
public class constructor01{ public static void main(String[] args){ Dog mydog = new Dog(); //使用的是默认的无参构造器 } class Dog { // 默认无参构造器 /* Dog(){ } */ }
🔴一旦定义了自己的构造器,默认的构造器就被覆盖,无法使用。除非显式的定义一下:Dog(){}
public class constructor01{ public static void main(String[] args){ Dog mydog = new Dog(); //使用的是默认的无参构造器,如果有了自己的构造器这个就不能用了 } class Dog { // 一旦定义了自己的构造器,默认的构造器就被覆盖,无法使用 public Dog(String dname){ //... } // 除非显式的定义一下无参构造器:Dog(){} Dog(){ } }
6.7.4 引入构造器之后的对象创建的流程分析
对象真正在堆里,p本质上是对象的引用哦!
对象中的空间首先是默认值初始化–之后是类属性的显式初始化–最后才是构造器初始化
🔺🔺步骤解释:
首先,在方法区先加载Person类信息(Person.class),只会加载一次,加载类的属性和方法;
第二步骤,new Person 的时候在堆里面创建一个空间,有一个地址;
第三步骤,完成对象的初始化:
1.创建时默认初始化 age =0,name = null,
2.显式初始化(类属性) age = 90,name = null,
3.最后构造器初始化 age =20,name = 小倩
第四步骤,将对象在堆中的地址返回给p。
6.8 this关键字
哪个对象调用该方法,该方法中的this就代表哪个对象!!!
public class This01{
public static void main(String[] args){
Dog mydog = new Dog("xiaoming", 12);
System.out.println(mydog.name);
System.out.println(mydog.age);
}
}
class Dog{
int age;
String name;
// 希望把构造器的形参直接写成属性名 但是出现变量的作用域的问题:
// 构造器的name是局部变量 而不是属性 ;构造器的age是局部变量 而不是属性
// ————于是引入this关键字——区分:类的属性和局部变量
public Dog(String name, int age){ //构造器
// this.name就是当前对象的属性name
this.name = name ;
// this.age就是当前对象的属性age
this.age = age ;
}
}
6.8.1 this关键字注意事项
- this 关键字可以用来访问本类的属性、方法、构造器
- 访问类的属性:this 用于区分当前类的属性和局部变量 (见上面的例子)
- 访问成员方法的语法:
this.方法名(参数列表)
- 访问构造器语法:
this(参数列表);
注意只能在构造器中使用!(即只能在构造器中访问另外一个构造器, 必须放在第一 条语句) - this 不能在类定义的外部使用,只能在类定义的方法中使用。
6.9 一些题目例子(综合使用 &匿名对象)
2.分析程序:
public class Test{
int count = 9; // Test类的属性
public void count1(){ // Test类的成员方法
count = 10;
System.out.println("count1 = " + count);
}
public void count2(){ // Test类的成员方法
System.out.println("count1 = " + count++);
}
public static void main(String[] args){ //这是Test类的main方法 任何一个类都可以有main方法
// 1.new Test() 是匿名对象(没有人引用他)
// 2.new Test().count1():在堆中新建一个Test类的匿名对象后,随即调用count1(),打印count=10
// 3.匿名对象特点:由于没人引用他,所以只能使用一次 使用后会被销毁。随后就被销毁
new Test().count1();
// 4. 在堆中新建一个Test对象,在栈中t1指向他 堆中的count属性:count =9
// 5. t1.count2(); t1对象调用count2,count++ 先打印输出再自增
yingyong
Test t1 = new Test();
t1.count2(); //输出9 之后自增
t1.count2(); //输出10 之后自增
}
}
// 输出:
// count1 = 10
// count1 = 9
// count1 = 10
其他
-
Math.random()
返回double类型的[0.0,1.0]的随机数System.out.println(Math.random());
-
字符串比较是否相等
String name = "啦啦啦"; System.out.println("啦啦啦".equals(name)) // 可以避免空指针
-
求幂次
Math.pow(2,3) // 2^3
-
三元运算符:
条件表达式 ? 表达式1 : 表达式2
return num%2==0 ? true: false;
-
javap 可以对class文件提供的字节码进行反编译。
-
hashCode()方法 返回对象的哈希码值 将对象的内部地址转化为一个整数 可以用来判断对象是否一样。