字面量
- 直接写出来的人可以理解的数据,在java中叫做字面量。
- 字面量分类:
数据类型分类
数据类型与内存
- 不同的数据类型分配了不同的内存空间,不同的内存空间,所存储的数据大小是不一样的。
- 数据类型内存占用和取值范围:
说明:E+38表示:乘以10的38次方。同理E-45表示:乘以10的负45次方。
java中,默认整数使用int型,浮点数使用double型
变量
- 变量就是内存中的存储空间,空间中存储的数据是可以发生改变。
- 变量的定义:
数据类型 变量名 = 变量值; - 变量的注意事项:
变量名不能重复
变量未赋值,不能使用
定义long类型变量,数据后面加L,如 long a = 100000000000L;
定义float类型变量,数据后面加F,如 float b = 10.33F;
标识符
- 标识符:就是给类,方法,变量等起名字的符号,由数字、字母、下划线(_)和美元符($)组成。可以理解为,标识符就是自定义命名的变量名、类名、方法名等等
如: b2、_2b、bj - 标识符注意事项:
不能以数字开头
不能是关键字
区分大小写
命名规范
小驼峰命名法,通常命名方法,变量
约定1:标识符一个单词的时候,首字母小写
范例1:name
约定2:标识符是多个单词的时候,第一个单词首字母小写,其他单词首字母大写
范例2:firstName
大驼峰命名法,通常命名类
约定1:标识符一个单词的时候,首字母大写
范例1:Hello
约定2:标识符是多个单词的时候,每个单词首字母大写
范例2:HelloWorld
运算
- 整数运算只能得到整数,要想得到小数,必须有浮点数参与运算。
package ithm; public class CountTest { public static void main(String[] args) { System.out.println(6 / 4); // 输出1 ,因为整数运算只能得到整数,要想得到小数,必须有浮点数的参与 System.out.println(6.0 / 4); // 输出1.5 ,因为整数运算只能得到整数,要想得到小数,必须有浮点数的参与 } }
- 运算中,我们要求参与运算的变量,数据类型要保持一致。 如果类型不一致,那么java会自动对其进行隐式转换。
隐式数据类型转换与强制数据类型转换
- 隐式数据类型转换:
不同数据类型的变量进行运算的时候,会自动将内存占用小的数据类型变量,转换为内存占用大的数据类型,再进行计算。
如下示例:
int型变量占用4字节内存,double型变量占用8字节内存,那么int型和double型变量进行运算,会自动先将int型变量转为double型变量,之后再进行运算,得到的结果也是double型变量的数据
package ithm; public class CountTest { public static void main(String[] args) { int a = 10; double b = 13.14; System.out.println(a + b); // 输出23.14 } }
- 但是如果规定了计算结果的数据类型为内存占用小的数据类型,那么不同数据类型的变量就不能进行运算,如下:
int 型占用4字节内存,double型占用8字节内存,所以当int 型变量a和double型变量b进行运算,同时用int型变量res接收运算结果,是会报错的
package ithm; public class CountTest { public static void main(String[] args) { int a = 10; // int 型占用4字节内存 double b = 13.14; // double型占用8字节内存 int res = a + b; // 如果规定了计算结果的数据类型为内存占用小的数据类型,那么不同数据类型的变量就不能进行运算,会报错 } }
-
而如果规定了计算结果的数据类型为内存占用大的数据类型,那么不同数据类型的变量就可以进行运算,如下:
int 型占用4字节内存,double型占用8字节内存,所以当int 型变量a和double型变量b进行运算,同时用double型变量j接收运算结果,是会报错的
package ithm; public class CountTest { public static void main(String[] args) { int a = 10; // int 型占用4字节内存 double b = 13.14; // double型占用8字节内存 double j = a + b; // 如果规定了计算结果的数据类型为内存占用大的数据类型,那么不同数据类型的变量就可以进行运算 System.out.println(j); // 输出23.14,自动将数据类型进行了隐式转换 } }
- 强制数据类型转换:
当不同的数据类型变量进行运算的时候,我们可以对变量进行强制数据类型转换,使其结果变成指定的数据类型,但是不推荐强制数据类型转换,因为不同数据类型的变量,所占用的内存大小是不一样的,有可能会造成数据的不准确(部分数据丢失)
强制数据类型转换,即把一个表示数据范围大的数值或者变量赋值给另一个表示数据范围小的变量。
格式:数据类型 变量名 = (目标数据类型)(数值或者变量)
package ithm; public class CountTest { public static void main(String[] args) { int a = 10; // int 型占用4字节内存 double b = 13.14; // double型占用8字节内存 int res = (int)(a + b); // 对运算结果进行强制数据类型转换,使得double型数据变成int型数据 System.out.println(res); // 输出23,可见强制数据类型转换,数据不准确 } }
字符型变量相加
- 字符型变量相加,是将字符型变量对应的ASCII码进行相加,所得到的结果是int 型数据,而不是字符拼接。(java中字符是单引号包裹的)
package ithm; public class CountTest { public static void main(String[] args) { char a = 'a'; // 字符型变量,对应的ASCII码是97 char b = 'b'; // 字符型变量,对应的ASCII码是98 System.out.println(a+b); // 输出195,字符型变量相加,是将字符型变量对应的ASCII码进行相加,所得到的结果是int 型数据,而不是字符拼接 } }
字符串相加
- 字符串相加,得到的结果是字符串拼接(java中字符串是双引号包裹的)
package ithm; public class CountTest { public static void main(String[] args) { char a = "a"; // 字符串变量 char b = "b"; // 字符串变量 System.out.println(a+b); // 输出ab,字符串相加,得到的结果是字符串拼接(java中字符串是双引号包裹的) } }
运算顺序
- java中的运算是按照顺序进行的,如下示例:
package ithm; public class CountTest { public static void main(String[] args) { System.out.println("hello"+ 666 + 7); // 输出hello6667,hello+666结果是字符串hello666,所以最终结果是hello6667 System.out.println(1 + 6 +"hello"); // 输出7hello,1 + 6结果是int型数据7,所以最终结果是7hello } }
扩展的赋值运算符
- 扩展的赋值运算符隐含了对运算结果的强制类型转换:
扩展的赋值运算符有 +=、-=、*=、/=、%=
package ithm; public class CountTest { public static void main(String[] args) { short a = 1; // 定义short型变量a a += 3; // 扩展的赋值运算符对运算结果做了强制类型转换,将结果转成了与a类型一致的short型数据 System.out.println(a); // 输出4 } }
package ithm; public class CountTest { public static void main(String[] args) { short a = 1; // 定义short型变量a // a += 3; // 扩展的赋值运算符对运算结果做了强制类型转换,将结果转成了与a类型一致的short型数据 // a = a + 3; // 报错,a += 3 并不等价于 a = a + 3,因为 a += 3 是对结果做了强制类型转换,使其变成与a类型一致的short型数据 a = (short)(a + 3); // a += 3 等价于 (short)(a + 3), 即对输出结果做了强制类型转换,使其变成与a类型一致的short型数据 System.out.println(a); // 输出4 } }
循环
- for循环语句
- while循环语句
- do…while循环语句
三种循环语句的区别:
for循环和while循环先判断条件是否成立,然后决定是否执行循环体(先判断后执行)
do…while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断)for和while的区别:
条件控制语句所控制的自增变量,因为归属for循环的语法结构中,在for循环结束后,就不可以继续使用了
条件控制语句所控制的自增变量,对于while循环来说不归属其语法结构中,在while循环结束后,还可以继续使用死循环格式
for(;;){} while(true) {} do{}while(true);
方法重载
- 方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载
- 多个方法在同一个类中
- 多个方法具有相同的方法名
- 多个方法的参数类型不同或者参数数量不同
- 方法重载的特点
- 类型不同或者数量不同重载仅对应方法的定义,与方法的调用无关,调用方式参照标准格式
- 重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关,换句话说不能通过返回值来判定两个方法是否相互构成重载
- 方法重载应用:主要用于方法的参数兼容
如:使用方法重载的思想,设计比较两个整数是否相等的方法,兼容全整数类型(byte,short,int,long)
package ithm; public class CountTest { public static void main(String[] args) { System.out.println(compare(10,20)); System.out.println(compare((byte) 1,(byte) 20)); System.out.println(compare((short) 10,(short) 20)); System.out.println(compare(10L,20L)); } // int public static boolean compare(int a,int b) { System.out.println("int"); return a == b; } // byte public static boolean compare(byte a,byte b) { System.out.println("byte"); return a == b; } // short public static boolean compare(short a,short b) { System.out.println("short"); return a == b; } // long public static boolean compare(long a,long b) { System.out.println("long"); return a == b; } }
类和对象
- 类
- 类的理解
- 类是对现实生活中一类具有共同属性和行为的事物的抽象;
- 类是对象的数据类型,类是具有相同属性和行为的一组对象的集合;
- 我们可以将其理解为对象的设计图,是对现实事物的一种描述。(比如手机,所有的手机都可以是一个类,因为它们都有摄像头、屏幕,都能打电话发短信,这是手机这类的共同属性和行为;区别仅是每部手机的外观、配置、品牌、生产日期不同,这是每个对象的具体特性)
- 类的组成
- 属性:指事物的特征,例如:手机事物(品牌,价格,尺寸)
- 行为:指事物能执行的操作,例如:手机事物(打电话,发短信)
- 类和对象的关系
- 类:类是对现实生活中一类具有共同属性和行为的事物的抽象
- 对象:是能够看得到摸的着的真实存在的实体
- 简单理解:类是对事物的一种描述,对象则为具体存在的事物
- 定义类:类的组成是由属性和行为两部分组成
- **属性:**在类中通过成员变量来体现(类中方法外的变量)
- **行为:**在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)
- 类的定义步骤:
① 定义类
② 编写类的成员变量
③ 编写类的成员方法
package ithm; public class Phone { // 成员变量 String brand; // 品牌 int price; // 标签 // 成员方法 public void call() { System.out.println("打电话"); } public void sendMessage() { System.out.println("发短信"); } }
- 对象
- 对象是能够看得到摸的着的真实存在的实体,比如手机这是一个大类,相当于是类的设计图或者框架,而iPhone13 pro max则是基于手机这一类的具象化的对象。
- 小结:类是对象的抽象,对象是类的实体。所有的事物都可以称为对象,所有的对象都有类别
package ithm; public class PhoneObject { public static void main(String[] args) { // 创建Phone的实例对象 Phone p = new Phone(); // 使用成员变量 p.brand = "华为"; p.price = 2000; System.out.println(p.brand); System.out.println(p.price); // 使用成员方法 p.call(); p.sendMessage(); } }
Java 内存分配
栈:所有局部变量都会在栈内存中创建
- 局部变量:定义在方法中的变量或者方法声明上的变量
- 方法执行都会加载到栈中进行
- 局部变量特点:随着方法的调用而存在,随着方法的调用完毕而消失
堆:所有对象及其对应的实例变量和数组都将存储在此
- 简单理解为:new出来的东西,都存储在堆内存
- 每一个new出来的东西都有一个地址值,使用完毕,会在垃圾回收器空闲时被回收
- 实例变量(成员变量)有初始化值:
基本数据类型:整数:0,浮点数:0.0,布尔:false,字符:空字符
引用数据类型:null
方法区:方法区存放被使用的类的字节码文件
- 字节码文件包含类的主方法和成员方法,以及类的成员变量
- 主方法和成员方法被调用和执行的时候,都是从方法区中的字节码文件中获取,然后加载到栈中去执行,执行完毕之后,再移除出栈
- 字节码文件中类的成员变量并不是对象的成员变量,对象的成员变量是依据字节码文件中类的成员变量进行创建并存储到堆中的
以如下代码为例说明程序执行时,在堆栈内存的变化
:
Student类
package com.tencent.member; import java.util.Scanner; // Scanner是java.util下的类,因此需要引入 public class Student { String name; // 定义成员变量 int age; // 定义成员变量 public void study() { // 定义成员方法 System.out.println("好好学习"); } }
- TestStudent类
package com.tencent.testDemo; import com.tencent.member.Student; // 引入Student public class TestStudent { public static void main(String[] args) { Student s1 = new Student(); // 创建Student实例s1 System.out.println(s1); // 打印s1地址 s1.name = "阿强"; s1.age = 23; System.out.println("姓名:" + s1.name + "; " + "年龄:" + s1.age); s1.study(); Student s2 = new Student(); // 创建Student实例s2 System.out.println(s2); // 打印s2地址 s2.name = "阿珍"; s2.age = 24; System.out.println("姓名:" + s2.name + "; " + "年龄:" + s2.age); s2.study(); } }
执行TestStudent类的代码解析: 1. 首先加载TestStudent的字节码文件到方法区 2. 执行TestStudent的main方法,因此从方法区中的TestStudent的字节码文件中找到main方法,并加载到栈内存中去执行 3. Student s1 = new Student(),用到了Student类,因此将Student类的字节码文件到方法区,同时由于new了Student的实例对象,因此在堆内存中开辟一片存储空间,存放s1,同时依据Student类的字节码文件中的成员变量,创建s1的成员变量。由于没给s1的成员变量赋值,因此存放在堆内存的s1的成员变量会有默认值,name的默认值是null,age的默认值是0.同时存储s1的内存,会有一片空间存放s1的成员方法地址,这个成员方法地址指向方法区中Student类字节码文件中的成员方法 4. System.out.println(s1); 打印s1的堆内存地址,如001 5. s1.name = "阿强";s1.age = 23; 根据s1的堆内存地址001,找到存放s1的内存空间,对s1的成员变量name和age赋值 6. System.out.println("姓名:" + s1.name + "; " + "年龄:" + s1.age); 根据s1的堆内存地址001,找到存放s1的内存空间,读取s1的成员变量name和age 7. s1.study(); 根据s1的堆内存地址001,找到存放s1的内存空间,并找到成员方法的地址,根据这个地址,找到存放在方法区中的Student类的字节码文件的成员方法study,并将study放入栈内存中执行,执行完毕之后,study方法移除出栈 8. Student s2 = new Student(),用到了Student类,由于之前创建s1的时候已经将Student类的字节码文件到方法区,因此不需要再重新加载Student类的字节码文件。由于new了Student的实例对象,因此在堆内存中开辟一片存储空间,存放s2,同时依据Student类的字节码文件中的成员变量,创建s2的成员变量。由于没给s2的成员变量赋值,因此存放在堆内存的s2的成员变量会有默认值,name的默认值是null,age的默认值是0.同时存储s2的内存,会有一片空间存放s2的成员方法地址,这个成员方法地址指向方法区中Student类字节码文件中的成员方法 9. System.out.println(s2); 打印s2的堆内存地址,如002 10. s2.name = "阿珍";s2.age = 24; 根据s2的堆内存地址002,找到存放s2的内存空间,对s2的成员变量name和age赋值 11. System.out.println("姓名:" + s2.name + "; " + "年龄:" + s2.age); 根据s2的堆内存地址002,找到存放s2的内存空间,读取s2的成员变量name和age 12. s2.study(); 根据s2的堆内存地址002,找到存放s2的内存空间,并找到成员方法的地址,根据这个地址,找到存放在方法区中的Student类的字节码文件的成员方法study,并将study放入栈内存中执行,执行完毕之后,study方法移除出栈 13. TestStudent的main方法执行完毕,将main方法移除出栈内存 14. 代码执行完毕,进程结束
备注:当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的),只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据。
内存中的垃圾回收
当堆内存中,创建对象或者数组所分配的内存空间而产生的地址,通过任何方式都不能被找到之后,就会被判定为内存中的“垃圾”,垃圾会被java垃圾回收器,空闲的时候自动进行清理。
如下:
把s1和s2设置为null的内存变化
如果把指向对象地址的s1和s2设置为null,那么就无法通过s1和s2访问对应内存的对象了,继续使用s1和s2去访问对象,会报空指针异常。当内存钟的对象没有变量能找到它的时候,就没人可以使用它了,那么它就会成为内存地址中的垃圾对象,会被java的垃圾回收器在空闲时清理
Student s1 = new Student(); Student s2 = new Student(); s1 = null; s2 = null;
成员变量和局部变量的区别
private关键字
和public一样,private是一个权限修饰符,可以修饰成员(成员变量和成员方法)。区别在于,private作用是保护成员不被别的类使用,被 private 修饰的成员只在本类中才能访问。
针对 private 修饰的成员变量,如果需要被其他类使用,提供两个相应的操作:
- 提供“get变量名()”方法,用于获取成员变量的值,方法用 public 修饰
- 提供“set变量名(参数)”方法,用于设置成员变量的值,方法用 public 修饰。
举个简单的例子,比如一个CreateMember类,里面的成员变量age,正常来说是一个大于0的正整数,为了保护age这个成员变量,避免其被违规修改(比如将age修改成-30,年龄不可能是负数,显然不合理),那么我们就得用private修饰age变量,并且提供一个setAge方法,控制age变量的合理化修改。
创建Member类
package ithm; public class Member { private String name; // 定义私有变量name,限定只能在本类中访问 private int age; // 定义私有变量age,限定只能在本类中访问 public void setAge(int num) { // 提供修改age的方法,避免其被违规修改 if (num > 0) { age = num; } else { System.out.println("请输入正整数"); } } public int getAge() { // 提供获取age的方法 return age; } public void setName(String str) { // 提供修改name的方法 name = str; } public String getName() { // 提供获取name的方法 return name; } }
在MemberDemo类中,创建Member类的实例对象,并修改和访问私有变量
package ithm; public class MemberDemo { public static void main(String[] args) { Member obj = new Member(); // 创建Member类的实例对象 obj.setName("张三"); // 因为私有变量name只能在Member类中访问,所以得通过Member类的公有方法去修改name obj.setAge(20); // 因为私有变量age只能在Member类中访问,所以得通过Member类的公有方法去修改age System.out.println("姓名:" + obj.getName()); // 因为私有变量name只能在Member类中访问,所以得通过Member类的公有方法去获取name System.out.println("年龄:" + obj.getAge()); // 因为私有变量age只能在Member类中访问,所以得通过Member类的公有方法去获取age } }
this关键字
- this限定的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)
① 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
如下:
package ithm; public class Member { private String name; // String类型的成员变量,默认值为null public void setName(String name) { // 提供修改name的方法 name = name; // 形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量,因此这个表达式是形参给形参赋值,成员变量name还是默认值null } public String getName() { // 提供获取name的方法 return name; } }
package ithm; public class MemberDemo { public static void main(String[] args) { Member obj = new Member(); // 创建Member类的实例对象 obj.setName("张三"); // 调用obj对象的成员方法 System.out.println("姓名:" + obj.getName()); // 输出姓名:null } }
- ②方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
如下:
package ithm; public class Member { private String name; public void setName(String str) { // 参没有与成员变量同名,不带this修饰的变量指的是成员变量 name = str; } public String getName() { // 提供获取name的方法 return name; } }
package ithm; public class MemberDemo { public static void main(String[] args) { Member obj = new Member(); // 创建Member类的实例对象 obj.setName("张三"); // 调用obj对象的成员方法 System.out.println("姓名:" + obj.getName()); // 输出姓名:张三 } }
- 什么时候使用this呢?防止局部变量与成员变量同名的情况下(如方法的形参与成员变量同名),成员变量不起作用
如下:
package ithm; public class Member { private String name; public void setName(String name) { // 提供修改name的方法 this.name = name; } public String getName() { // 提供获取name的方法 return this.name; } }
- this:方法被哪个对象调用,this就代表哪个对象
如下:getName被obj调用,那么this代表obj
package ithm; public class Member { private String name; public void setName(String name) { // 提供修改name的方法 this.name = name; } public String getName() { // 提供获取name的方法 return this.name; } }
package ithm; public class MemberDemo { public static void main(String[] args) { Member obj = new Member(); // 创建Member类的实例对象 obj.setName("张三"); // 调用obj对象的成员方法 System.out.println("姓名:" + obj.getName()); // 调用obj对象的成员方法,此时getName里的this指向obj } }
封装
封装是面向对象三大特征之一(封装,继承,多态),是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的
封装原则:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问,比如private关键字定义成员变量,提供对应的getXxx()/setXxx()方法
封装好处:①通过方法来控制成员变量的操作,提高了代码的安全性。②把代码用方法进行封装,提高了代码的复用性
构造方法
构造方法是一种特殊的方法,作用主要用于创建对象,例如初始化对象的成员变量的值。构造方法必须和类同名
① 构造方法的创建
如果没有定义构造方法,系统将给出一个默认的无参数构造方法。
如果定义了构造方法,系统将不再提供默认的构造方法,因此不管类中有没有定义带参构造方法,都建议永远先记着提供一个无参数构造方法
② 构造方法的重载
构造方法和普通方法一样,都支持方法重载。如果已经自定义了带参构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法
③ 构造方法的建议
不管类中有没有定义带参构造方法,都建议永远先记着提供一个无参数构造方法
④带参构造方法与无参构造方法
无参构造方法就是没有参数的构造方法,带参构造方法就是有参数的构造方法。其中带参构造方法通常用于创建对象的时候,给成员变量进行初始化赋值操作
package ithm; public class Member { private String name; // 定义私有变量name,限定只能在本类中访问 private int age; // 定义私有变量age,限定只能在本类中访问 public Member() {} // 如果定义了构造方法,系统将不再提供默认的构造方法,因此不管类中有没有定义带参构造方法,都建议永远先记着提供一个无参数构造方法 // 构造方法重载 public Member(String name, int age) { // 带参构造方法,一般用于创建对象时对成员变量进行初始化操作 this.name = name; this.age = age; } public void setAge(int num) { // 提供修改age的方法,避免其被违规修改 if (num > 0) { age = num; } else { System.out.println("请输入正整数"); } } public int getAge() { // 提供获取age的方法 return age; } public void setName(String str) { // 提供修改name的方法 name = str; } public String getName() { // 提供获取name的方法 return name; } }
package ithm; public class MemberDemo { public static void main(String[] args) { Member obj = new Member("张三", 20); // 利用构造方法,在创建对象的时候对成员变量进行初始化操作 System.out.println("姓名:" + obj.getName()); // 输出 姓名:张三 System.out.println("年龄:" + obj.getAge()); // 输出 年龄:20 } }
JavaBean
JavaBean就是一个Java中的类,其对象可以用于在程序中封装数据,如学生类,手机类
标准 JavaBean 须满足如下要求:
①成员变量使用 private 修饰
②提供每一个成员变量对应的 setXxx() / getXxx()
③提供一个无参构造方法
如下就是一个标准的JavaBean
package ithm; public class Member { private String name; // 定义私有变量name,限定只能在本类中访问 private int age; // 定义私有变量age,限定只能在本类中访问 public Member() {} // 如果定义了构造方法,系统将不再提供默认的构造方法,因此不管类中有没有定义带参构造方法,都建议永远先记着提供一个无参数构造方法 public Member(String name, int age) { // 带参构造方法,一般用于创建对象时对成员变量进行初始化操作 this.name = name; this.age = age; } public void setAge(int num) { // 提供修改age的方法,避免其被违规修改 if (num > 0) { age = num; } else { System.out.println("请输入正整数"); } } public int getAge() { // 提供获取age的方法 return age; } public void setName(String str) { // 提供修改name的方法 name = str; } public String getName() { // 提供获取name的方法 return name; } }
package ithm; public class MemberDemo { public static void main(String[] args) { // 无参构造方法+set方法 Member obj1 = new Member(); obj1.setName("张三"); obj1.setAge(20); System.out.println("姓名:" + obj1.getName()); // 输出 姓名:张三 System.out.println("年龄:" + obj1.getAge()); // 输出 年龄:20 // 带参构造方法 Member obj2 = new Member("李四", 30); System.out.println("姓名:" + obj2.getName()); // 输出 姓名:李四 System.out.println("年龄:" + obj2.getAge()); // 输出 年龄:30 } }
API
- 什么是API
指的就是 JDK 中提供的各种功能的 Java类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可,我们可以通过帮助文档来学习这些API如何使用。(实际上就是一些方法,类似前端的forEach、split之类的) - Scanner类
next() : 遇到了空格, 就不再录入数据了 , 结束标记: 空格, tab键
nextLine() : 可以将数据完整的接收过来 , 结束标记: 回车换行符
package com.tencent.api; import java.util.Scanner; public class Demo1Scanner { /* next() : 遇到了空格, 就不再录入数据了 结束标记: 空格, tab键 nextLine() : 可以将数据完整的接收过来 结束标记: 回车换行符 */ public static void main(String[] args) { // 1. 创建Scanner对象 Scanner sc = new Scanner(System.in); System.out.println("请输入:"); // 2. 调用nextLine方法接收字符串 // ctrl + alt + v : 快速生成方法的返回值 String s = sc.nextLine(); System.out.println(s); } }
package com.tencent.api; import java.util.Scanner; public class Demo2Scanner { /* nextInt和nextLine方法配合使用的时候, nextLine方法就没有键盘录入的机会了 建议: 今后键盘录入数据的时候, 如果是字符串和整数一起接受, 建议使用next方法接受字符串. */ public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入整数:"); int num = sc.nextInt(); // 10 + 回车换行 System.out.println("请输入字符串:"); String s = sc.nextLine(); System.out.println(num); System.out.println(s); } }
- String类1、String 类在 java.lang 包下,所以使用的时候不需要导包2、String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都是实现为此类的实例也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象3、字符串对象是不能改的,s1的多次修改,只是修改s1指向到另一个字符串对象的存储地址罢了,原字符串对象并没有被修改,只是会在空闲的时候被垃圾回收器回收4、String这个类比较特殊,打印其对象的时候,不会出现内存地址,而是该对象所记录的真实内容
package com.itheima.string; public class Demo2StringConstructor { /* String类常见构造方法: public String() : 创建一个空白字符串对象,不含有任何内容 public String(char[] chs) : 根据字符数组的内容,来创建字符串对象 public String(String original) : 根据传入的字符串内容,来创建字符串对象 String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc 注意: String这个类比较特殊, 打印其对象名的时候, 不会出现内存地址 而是该对象所记录的真实内容. 面向对象-继承, Object类 */ public static void main(String[] args) { // public String() : 创建一个空白字符串对象,不含有任何内容 String s1 = new String(); System.out.println(s1); // public String(char[] chs) : 根据字符数组的内容,来创建字符串对象 char[] chs = {'a','b','c'}; String s2 = new String(chs); System.out.println(s2); // public String(String original) : 根据传入的字符串内容,来创建字符串对象 String s3 = new String("123"); System.out.println(s3); } }
- 5、创建字符串对象的区别对比:
- 通过构造方法创建
通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同 - 直接赋值方式创建
以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串常量池中维护
通过双引号创建的字符串,会先在方法区中的字符串常量池中做匹配,如果不存在这个字符串,则将这段字符串在字符串常量池中创建。如果存在,不会重新创建,而是直接复用这个字符串的内存地址
- 创建字符串的常见情况分析
案例1:
String s1 = "abc"; // 字符串方式创建s1,abc会放入常量池中 String s2 = new String("abc");// 先通过字符串方式创建abc对象,之后再以new的形式开辟新的内存空间,创建字符串对象,所以这一步是创建了两个字符串对象 System.out.println(s1 == s2); // false,String是引用数据类型,s1和s2地址值不同,所以是false
- 案例2:
String s1 = "abc"; String s2 = "ab"; String s3 = s2 + "c"; System.out.println(s1 == s3); // false, 字符串之间使用 + 号拼接的时候,系统底层会自动创建一个StringBuilder对象,然后再调用其append方法完成拼接,拼接后,再调用toString方法将StringBuilder对象转为String对象
-
案例3:
String s1 = "abc"; String s2 = "a" + "b" + "c"; System.out.println(s1 == s2); // true,这里虽然出现了字符串拼接,但是”a”, ”b”, ”c”的直接拼接,是属于字符串常量的拼接,而java存在常量优化机制,s2就直接指向常量池中的”abc”,与s1所指向的地址一致,因此为true
- 字符串比较
字符串是对象,它比较内容是否相同,是通过一个方法来实现的,这个方法叫equals
public boolean equals(String s); // 将此字符串与指定对象进行比较,由于我们比较的是字符串对象,所以参数直接传递一个字符串
- 常见字符串操作案例
①遍历字符串
package com.itheima.test; import java.util.Scanner; public class Test2 { /* 需求:键盘录入一个字符串,使用程序实现在控制台遍历该字符串 思路: 1. 键盘录入一个字符串,用 Scanner 实现 2. 遍历字符串,首先要能够获取到字符串中的每一个字符 public char charAt(int index):返回指定索引处的char值,字符串的索引也是从0开始的 3. 遍历字符串,其次要能够获取到字符串的长度 public int length():返回此字符串的长度 4. 遍历打印 9 */ public static void main(String[] args) { // 1. 键盘录入一个字符串,用 Scanner 实现 Scanner sc = new Scanner(System.in); System.out.println("请输入:"); String s = sc.nextLine(); // 2. 遍历字符串,首先要能够获取到字符串中的每一个字符 for(int i = 0; i < s.length(); i++){ // i : 字符串的每一个索引 char c = s.charAt(i);· System.out.println(c); } } }
- ②统计字符出现次数,大写、小写、数字
package com.itheima.test; import java.util.Scanner; public class Test3 { /* 1. 键盘录入一个字符串,用 Scanner 实现 2. 将字符串拆分为字符数组 , public char[] toCharArray( ):将当前字符串拆分为字符数组并返回 3. 遍历字符数 */ public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入:"); String s = sc.nextLine(); int bigCount = 0; int smallCount = 0; int numCount = 0; // 2. 将字符串拆分为字符数组 char[] chars = s.toCharArray(); // 3. 遍历字符数组 for (int i = 0; i < chars.length; i++) { char c = chars[i]; if (c >= 'A' && c <= 'Z') { bigCount++; } else if (c >= 'a' && c <= 'z') { smallCount++; } else if (c >= '0' && c <= '9') { numCount++; } } System.out.println("大写字母字符数量:" + bigCount); System.out.println("小写字母字符数量:" + smallCount); System.out.println("数字字符数量:" + numCount); } }
- ③字符串截取,以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽,最终效果为:156****1234
package com.itheima.test; import java.util.Scanner; public class Test5 { /* 需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽 最终效果为:156****1234 思路: 1. 键盘录入一个字符串,用 Scanner 实现 2. 截取字符串前三位 3. 截取字符串后四位 4. 将截取后的两个字符串,中间加上****进行拼接,输出结果 */ public static void main(String[] args) { // 1. 键盘录入一个字符串,用 Scanner 实现 Scanner sc = new Scanner(System.in); System.out.println("请输入手机号:"); String telString = sc.nextLine(); // 2. 截取字符串前三位 String start = telString.substring(0,3); // 3. 截取字符串后四位 String end = telString.substring(7); // 4. 将截取后的两个字符串,中间加上****进行拼接,输出结果 System.out.println(start + "****" + end); } }
- ④敏感词替换-字符串替换
键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换
package com.itheima.test; import java.util.Scanner; public class Test6 { /* 需求:键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换 思路: 1. 键盘录入一个字符串,用 Scanner 实现 2. 替换敏感词 String replace(CharSequence target, CharSequence replacement) 将当前字符串中的target内容,使用replacement进行替换,返回新的字符串 3. 输出结果 */ public static void main(String[] args) { // 1. 键盘录入一个字符串,用 Scanner 实现 Scanner sc = new Scanner(System.in); System.out.println("请输入:"); String s = sc.nextLine(); // 2. 替换敏感词 String result = s.replace("TMD","***"); // 3. 输出结果 System.out.println(result); } }
- ⑤切割字符串
以字符串的形式从键盘录入学生信息,例如:“张三 , 23”,从该字符串中切割出有效数据,封装为Student学生对象
package com.itheima.test; import com.itheima.domain.Student; import java.util.Scanner; public class Test7 { /* 需求:以字符串的形式从键盘录入学生信息,例如:“张三 , 23” 从该字符串中切割出有效数据,封装为Student学生对象 思路: 1. 编写Student类,用于封装数据 2. 键盘录入一个字符串,用 Scanner 实现 3. 根据逗号切割字符串,得到(张三)(23) String[] split(String regex) :根据传入的字符串作为规则进行切割 将切割后的内容存入字符串数组中,并将字符串数组返回 4. 从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象 5. 调用对象getXxx方法,取出数据并打印。 */ public static void main(String[] args) { // 2. 键盘录入一个字符串,用 Scanner 实现 Scanner sc = new Scanner(System.in); System.out.println("请输入学生信息:"); String stuInfo = sc.nextLine(); // stuInfo = "张三,23"; // 3. 根据逗号切割字符串,得到(张三)(23) String[] sArr = stuInfo.split(","); // System.out.println(sArr[0]); // System.out.println(sArr[1]); // 4. 从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象 Student stu = new Student(sArr[0],sArr[1]); // 5. 调用对象getXxx方法,取出数据并打印。 System.out.println(stu.getName() + "..." + stu.getAge()); } }
- String类的常用方法
public boolean equals(Object anObject) 比较字符串的内容,严格区分大小写
public boolean equalsIgnoreCase(String anotherString) 比较字符串的内容,忽略大小写
public int length() 返回此字符串的长度
public char charAt(int index) 返回指定索引处的 char 值
public char[] toCharArray() 将字符串拆分为字符数组后返回
public String substring(int beginIndex, int endIndex) 根据开始和结束索引进行截取,得到新的字符串(包含头,不包含尾)
public String substring(int beginIndex) 从传入的索引处截取,截取到末尾,得到新的字符串
public String replace(CharSequence target, CharSequence replacement) 使用新值,将字符串中的旧值替换,得到新的字符串
public String[] split(String regex) 根据传入的规则切割字符串,得到字符串数组
- StringBuilder类概述 :StringBuilder 是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuilder 对象中的内容是可变的。StringBuilder可以接收任何类型的参数,并将参数转为String类型StringBuilder类和String类的区别 :
- **String类:**内容是不可变的
- **StringBuilder类:**内容是可变的
- **注意:**打印String对象和StringBuilder对象都只会出现内容,不会出现地址
- StringBuilder类的构造方法 :
常用的构造方法
方法名 | 说明 |
public StringBuilder() | 创建一个空白可变字符串对象,不含有任何内容 |
public StringBuilder(String str) | 根据字符串的内容,来创建可变字符串对象 |
- 示例代码
public class StringBuilderDemo01 { public static void main(String[] args) { //public StringBuilder():创建一个空白可变字符串对象,不含有任何内容 StringBuilder sb = new StringBuilder(); System.out.println("sb:" + sb); System.out.println("sb.length():" + sb.length()); //public StringBuilder(String str):根据字符串的内容,来创建可变字符串对象 StringBuilder sb2 = new StringBuilder("hello"); System.out.println("sb2:" + sb2); System.out.println("sb2.length():" + sb2.length()); } }
- StringBuilder常用的成员方法 :
- 添加和反转方法
方法名 | 说明 |
public StringBuilder append(任意类型) | 添加数据,并返回对象本身 |
public StringBuilder reverse() | 返回相反的字符序列 |
public class StringBuilderDemo01 { public static void main(String[] args) { //创建对象 StringBuilder sb = new StringBuilder(); //public StringBuilder append(任意类型):添加数据,并返回对象本身 // StringBuilder sb2 = sb.append("hello"); // // System.out.println("sb:" + sb); // System.out.println("sb2:" + sb2); // System.out.println(sb == sb2); // sb.append("hello"); // sb.append("world"); // sb.append("java"); // sb.append(100); //链式编程 sb.append("hello").append("world").append("java").append(100); System.out.println("sb:" + sb); //public StringBuilder reverse():返回相反的字符序列 sb.reverse(); System.out.println("sb:" + sb); } }
- StringBuilder和String相互转换【应用】
- StringBuilder转换为String
public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String - String转换为StringBuilder
public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder
public class StringBuilderDemo02 { public static void main(String[] args) { /* //StringBuilder 转换为 String StringBuilder sb = new StringBuilder(); sb.append("hello"); //String s = sb; //这个是错误的做法 //public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String String s = sb.toString(); System.out.println(s); */ //String 转换为 StringBuilder String s = "hello"; //StringBuilder sb = s; //这个是错误的做法 //public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder StringBuilder sb = new StringBuilder(s); System.out.println(sb); } }
- StringBuilder拼接字符串案例
案例需求 :
定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
并在控制台输出结果。例如,数组为int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]
实现步骤 :
- 定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
- 定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
返回值类型 String,参数列表 int[] arr - 在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
- 调用方法,用一个变量接收结果
- 输出结果
- 代码实现 :
/* 思路: 1:定义一个 int 类型的数组,用静态初始化完成数组元素的初始化 2:定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。 返回值类型 String,参数列表 int[] arr 3:在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回 4:调用方法,用一个变量接收结果 5:输出结果 */ public class StringBuilderTest01 { public static void main(String[] args) { //定义一个 int 类型的数组,用静态初始化完成数组元素的初始化 int[] arr = {1, 2, 3}; //调用方法,用一个变量接收结果 String s = arrayToString(arr); //输出结果 System.out.println("s:" + s); } //定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回 /*1111111111111111111111111111111111111111111111111111111 两个明确: 返回值类型:String 参数:int[] arr */ public static String arrayToString(int[] arr) { //在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回 StringBuilder sb = new StringBuilder(); sb.append("["); for(int i=0; i<arr.length; i++) { if(i == arr.length-1) { sb.append(arr[i]); } else { sb.append(arr[i]).append(", "); } } sb.append("]"); String s = sb.toString(); return s; } }
- StringBuilder的append拼接知识点:
- append返回的是对象自己,因此可以链式编程
sb.append("hello").append("world").append("java").append(100);
- append是拼接,由此可见StringBuilder是一个可变的字符串类
- String对象只要出现了+号拼接,就会在堆内存开辟空间生成StringBuilder对象,并调用append方法进行拼接
之后自动调用toString把StringBuilder转成String
上图可以看出String对象只要出现了一次+号拼接,就会生成新的StringBuilder和String,太浪费内存和线程了。
因此直接用StringBuilder拼接,无论是多少次拼接,都只会有一个StringBuilder在处理,不需要额外创建多个StringBuilder,因此不占用内存和效率。如果想获取String类型,直接调用toString即可
如果字符串涉及大量拼接,最好是使用StringBuilder进行拼接
== 比较
- == 比较基本数据类型:比较的是具体的值
- == 比较引用数据类型:比较的是对象地址值
包
①包作用: 其实就是文件夹,主要作用是对类进行分类管理。用前端思维来说,包也就是一个类似npm包一样的东西
②包命名规则:
个人:
indi:多人完成,版权属于发起者
包名为indi.发起者名.项目名.模块名*.*.\*
个人:
pers :独自完成,公开,版权主要属于个人。
包名为pers.个人名.项目名.模块名*.*.*
个人:
priv : 独自完成,非公开,版权属于个人。
包名为priv.个人名.项目名.模块名*.*.*
团队:
team:团队项目指由团队发起,并由该团队开发的项目,版权属于该团队所有。
包名为team.团队名.项目名.模块名*.*.*
公司:
com:由公司发起,版权由项目发起的公司所有。
包名为com.公司名.项目名.模块名*.*.*
示例:比如公司名是tencent,那么可以创建一个主包com.tencent,再在com.tencent下创建子包member和testDemo,子包member下有类Member,子包testDemo下有类CreateMember
③包引入
使用不同包下的类时,使用的时候要写类的全路径,写起来太麻烦了。(java.lang包下的类在使用的时候不需要导包)
package com.tencent.testDemo; public class CreateMember { public static void main(String[] args) { // 无参构造方法+set方法 com.tencent.member.Member obj1 = new com.tencent.member.Member(); // 使用不同包下的类时,使用的时候要写类的全路径 obj1.setName("张三"); obj1.setAge(20); System.out.println("姓名:" + obj1.getName()); // 输出 姓名:张三 System.out.println("年龄:" + obj1.getAge()); // 输出 年龄:20 // 带参构造方法 com.tencent.member.Member obj2 = new com.tencent.member.Member("李四", 30); // 使用不同包下的类时,使用的时候要写类的全路径 System.out.println("姓名:" + obj2.getName()); // 输出 姓名:李四 System.out.println("年龄:" + obj2.getAge()); // 输出 年龄:30 } }
为了简化带包的操作,Java就提供了导包的功能。
导包的格式
格式:import 包名;
范例:
import com.tencent.member.*; // 引入com.tencent.member包下的所有类 import com.tencent.member.Member; // 引入com.tencent.member包下的Member类
package com.tencent.testDemo; //import com.tencent.member.*; // 引入com.tencent.member包下的所有类 import com.tencent.member.Member; // 引入com.tencent.member包下的Member类 public class CreateMember { public static void main(String[] args) { // 无参构造方法+set方法 Member obj1 = new Member(); obj1.setName("张三"); obj1.setAge(20); System.out.println("姓名:" + obj1.getName()); // 输出 姓名:张三 System.out.println("年龄:" + obj1.getAge()); // 输出 年龄:20 // 带参构造方法 Member obj2 = new Member("李四", 30); System.out.println("姓名:" + obj2.getName()); // 输出 姓名:李四 System.out.println("年龄:" + obj2.getAge()); // 输出 年龄:30 } }
④包引入与使用示例:
一、写一个Student类
二、学生姓名和年龄读取键盘输入的数据。(通过System.in获取输入流,通过Scanner获取键盘输入流并解析出字符串。System是java.long下的类,因此不需要引入;Scanner是java.util下的类,因此需要引入)
三、写一个StudentDemo类,调用Student生成Student对象实例。StudentDemo与Student处于不同的package
Student
package com.tencent.member; import java.util.Scanner; // Scanner是java.util下的类,因此需要引入 public class Student { private String name; // 定义成员变量 private int age; // 定义成员变量 public Student() { // 定义构造方法 Scanner sc = new Scanner(System.in); // 创建键盘录入数据对象,读取键盘输入的数据。(通过System.in获取输入流,通过Scanner获取键盘输入流并解析出字符串。) // System是java.long下的类,因此不需要引入 // Scanner是java.util下的类,因此需要引入 System.out.println("请输入姓名"); this.name = sc.next(); // 通过键盘录入数据对象调用nextInt()方法获取字符串 System.out.println("请输入年龄"); this.age = sc.nextInt(); // 通过键盘录入数据对象调用nextInt()方法获取整数 } public void printInfo() { // 定义成员方法 System.out.println("姓名" + name); System.out.println("年龄" + age); } }
StudentDemo
package com.tencent.testDemo; import com.tencent.member.Student; // 引入Student public class StudentDemo { public static void main(String[] args) { Student obj = new Student(); // 创建Student实例 obj.printInfo(); // 调用成员方法 } }
GUI
①Graphical User Interface(图形用户接口),即java提供了可实现简单的前端界面窗口的api。
②创建GUI一般有两个包:
ava.awt 包:
Abstract Window ToolKit (抽象窗口工具包),需要调用本地系统方法实现功能,属重量级控件
javax.swing 包:
在awt的基础上,建立的一套图形界面系统,提供了更多的组件,而且完全由Java实现。增强了移植性,属轻量级控件
③组件:是具有图形表示的对象,该图形表示可以显示在屏幕上并且可以与用户交互
④代码实现一个简单的聊天室GUI窗口
package com.tencent.testDemo; import javax.swing.*; // 引入javax.swing 包以获取常用的GUI组件类,如JFrame、JButton、JLabel、JTextArea、JTextField等 import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class GuiDemo { public static void main(String[] args) { JFrame jf = new JFrame(); // 创建窗体对象 jf.setTitle("深夜聊天室"); // 设置窗体标题 jf.setSize(400, 300); // 设置窗体大小 jf.setDefaultCloseOperation(3); // 设置关闭窗体,结束整个程序进程 jf.setLocationRelativeTo(null); // 设置窗体位于屏幕中央 jf.setAlwaysOnTop(true); // 设置窗体始终位于其他窗口之上 jf.setLayout(null); // 取消窗体默认布局 JLabel headerLabel = new JLabel("快来聊天吧"); // 创建文本 headerLabel.setBounds(10,10,360,20); // 设置文本在窗体的坐标系位置、宽高 jf.add(headerLabel); // 将文本加进窗体中 JTextArea msgArea = new JTextArea(); // 创建聊天记录区域 msgArea.setBounds(10,40,360,170); // 设置聊天记录区域在窗体的坐标系位置、宽高 jf.add(msgArea); // 将聊天记录区域加进窗体中 JTextField msgField = new JTextField(); // 创建文本框 msgField.setBounds(10,230,180,20); // 设置文本框在窗体的坐标系位置、宽高 jf.add(msgField); // 将文本框加进窗体中 JButton sendButton = new JButton("发送"); // 创建发送按钮 sendButton.setBounds(200,230,70,20); // 设置发送按钮在窗体的坐标系位置、宽高 jf.add(sendButton); // 将发送按钮加进窗体中 JButton clearButton = new JButton("清空"); // 创建清空按钮 clearButton.setBounds(280,230,70,20); // 设置清空按钮在窗体的坐标系位置、宽高 jf.add(clearButton); // 将清空按钮加进窗体中 // 添加发送按钮事件 sendButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String msg = msgField.getText(); // 获取输入框的值 System.out.println("发送"); msgArea.append("您发送的消息是" + msg + "\n"); // 给聊天记录区域赋值 msgField.setText(""); // 清空输入框 } }); // 添加清空按钮事件 clearButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("清空"); msgArea.setText(""); // 清空聊天记录区域 msgField.setText(""); // 清空输入框 } }); jf.setVisible(true); // 设置窗体可见 } }
String类常用api
①创建对象-String
String s1 = new String(); String s2 = new String("hello world"); System.out.println(s1); // 打印空字符串 System.out.println(s2); // 打印hello world
②长度-length
String s1 = new String("hello world"); int len = s1.length(); System.out.println(len); // 打印11
③比较-equals、equalsIgnoreCase
String s1 = new String("hello world"); String s2 = new String("HELLO WORLD"); Boolean isSame = s1.equals(s2); // equals比较,会对比大小写 Boolean isSameIgnoreCase = s1.equalsIgnoreCase(s2); // equalsIgnoreCase比较,会忽略大小写 System.out.println(isSame); // 打印false System.out.println(isSameIgnoreCase); // 打印true
④去除前后空格-trim
String s1 = new String(" hello world "); String s2 = s1.trim(); System.out.println(s2); // 打印s1去掉前后空格的字符串,即hello world
基本类型的包装类
①定义:
将基本数据类型数据组装成引用数据类型数据(对象),这就是包装类。拿String类举例,String类除了有取值范围外,还包含属性和方法,而基本数据类型只是一个取值范围,没有具体方法或者属性。sun公司想能否将每个的基本数据类型都提供一个引用类型,从而能否具有属性和方法,方便程序使用。所以推出包装类。
②包装类分类:
③以包装类Integer为例:
Integer类在对象中包装基本类型int的值
有以下构造方法:
Integer(int value):根据 int 值创建 Integer 对象(过时)
Integer(String s):根据 String 值创建 Integer 对象(过时)
Integer intA = new Integer(10); Integer intB = new Integer("20"); System.out.println(intA); // 打印10 System.out.println(intB); // 打印20
Integer的成员方法使用:
Integer成员方法有很多,我们拿min和max,sum举例
int min = Integer.min(2, 6); System.out.println(min);//2 int max = Integer.max(10, 20); System.out.println(max);//20 int sum = Integer.sum(8, 9); System.out.println(sum);//17
④自动装箱和拆箱
装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型
Integer i = 100; // 自动装箱 i += 200; // 等价于i = i + 200; 这个表达式有两个步骤: i + 200是自动拆箱; i = i + 200是自动装箱
static 修饰的静态成员方法和成员变量可以直接通过类名去访问,不需要创建实例对象
定义StaticClass类
package com.tencent.member; public class StaticClass { public StaticClass() {} public static void getMaxNum (int a, int b) { // static 修饰的静态成员方法和成员变量可以直接通过类名去访问,不需要创建实例对象 int res = a > b ? a : b; System.out.println(res); } }
定义StaticDemo类,使用StaticClass的静态方法
package com.tencent.testDemo; import com.tencent.member.StaticClass; // 引入com.tencent.member包下的Member类 public class StaticDemo { public static void main(String[] args) { StaticClass.getMaxNum(10, 20); // 直接通过类名使用static关键字定义的成员方法 } }
Date类
①定义:
Date类表示特定的时刻,精度为毫秒,其属于java.util下的类,因此使用时需要引入
②构造方法:
Date():分配 Date对象并对其进行初始化,使其表示分配时间,测量 Date到毫秒
Date(long date):分配 Date对象并初始化它以表示自标准基准时间以来的指定毫秒数,即1970年1月1日00:00:00
Date d1 = new Date(); System.out.println(d1); Date d2 = new Date(24*60*60*1000); System.out.println(d2);
③成员方法:
long getTime():获取的是日期对象从1970年1月1日 00:00:00到现在的毫秒值
void setTime(long time):设置时间,给的是毫秒值
Date d1 = new Date(); long time = d1.getTime(); System.out.println(time); d1.setTime(time - 24*60*60*1000); System.out.println(d1);
SimpleDateFormat类
①定义:
SimpleDateFormat 是主要用于格式化和解析日期的具体类,其属于java.text下的类,因此使用时需要引入。
日期和时间格式由日期和时间模式字符串指定,在日期和时间模式字符串中,从‘A’到‘Z’以及从‘a’到‘z’引号的字母被解释为表示日期或时间字符串的组件的模式字母
常用的模式字母及对应关系如下:
②构造方法:
SimpleDateFormat():构造一个SimpleDateFormat,使用默认模式和日期格式
SimpleDateFormat(String pattern):构造一个SimpleDateFormat使用给定的模式和默认的日期格式
③格式化(从 Date 到 String )
String format(Date date):将日期格式化成日期/时间字符串
④解析(从 String 到 Date )
Date parse(String source):从给定字符串的开始解析文本以生成日期
⑤使用
package com.tencent.testDemo; import java.text.SimpleDateFormat; import java.util.Date; import java.text.ParseException; public class DateDemo { public static void main(String[] args) { Date d1 = new Date(); SimpleDateFormat sdf1 = new SimpleDateFormat(); String str1 = sdf1.format(d1); System.out.println(str1); // 打印2023/8/1 下午6:45 SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); String str2 = sdf2.format(d1); System.out.println(str2); // 打印2023年08月01日 18:45:33 String timeStr = "2023-08-01 18:45:33"; SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date d2 = sdf3.parse(timeStr); System.out.println(d2); // 打印Tue Aug 01 18:45:33 CST 2023 } catch (Exception e) { System.out.println(e); } } }
数组
①数组定义格式:
格式1:数据类型[] 变量名; (推荐) 范例: int[] arr; 定义了一个int类型的数组,数组名是arr 格式2:数据类型 变量名[]; 范例: int arr[]; 定义了一个int类型的变量,变量名是arr数组
②数组初始化
Java中的数组必须先初始化,然后才能使用
所谓初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋值
注意:数组中的每一个数据,我们称之为数组中的元素
数组初始化方式分为静态初始化和动态初始化
静态初始化:初始化时指定每个数组元素的初始值,由系统决定数组长度 格式:数据类型[] 变量名 = new 数据类型[]{数据1,数据2,数据3,…}; 范例:int[] arr = new int[]{1,2,3}; 简化格式:数据类型[] 变量名 = {数据1,数据2,数据3,…}; 范例:int[] arr = {1,2,3}; 动态初始化:初始化时只指定数组长度,由系统为数组分配初始值 格式:数据类型[] 变量名 = new 数据类型[数组长度]; 范例:int[] arr = new int[3]; 使用场景: 静态初始化:开始就存入元素值,适合一开始就能确定元素值的业务场景 动态初始化:指定数组长度,后期赋值,适合开始知道数据的数量,但是不确定具体元素值的业务场景 注意:两种初始化的方式是独立的,不可以混用
③数组元素访问
数组名[索引]
④数组遍历
int[] arr = {1, 2, 3}; for (int i = 0; i < arr.length; i++) { arr[i]; //对元素arr[i]进行操作 }
⑤数组内存图
需要注意的是,如果把null赋值给数组,数组指针依旧会存在在栈内存当中,因为null是存于栈内存的,但是再次访问数组数据,就会报空指针异常,对象不再指向堆内存,访问失败。(所以我们推荐先判断数组是否为空,再访问数组元素)
package com.tencent.testDemo; public class ArrayClass { public static void main(String[] args) { int[] arr = new int[3]; System.out.println(arr); // 打印数组的存储地址[I@4eec7777 System.out.println(arr[2]); // 打印0 arr = null;// 把 null赋值给数组 System.out.println(arr); // 打印null // System.out.println(arr[0]); // 报错,空指针异常 if (arr != null) { System.out.println(arr[0]); } } }
⑥二维数组
二维数组:元素为一维数组的数组
定义格式:
数据类型[][] 变量名; int[][] arr; (推荐)
数据类型 变量名[][]; int arr[][];
数据类型[] 变量名[]; int[] arr[];
初始化:
和一维数组是一样的,静态初始化和动态初始化
静态初始化: 格式:数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…},…}; 范例:int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}}; 解读 定义了一个二维数组 二维数组中有三个元素(一维数组) 每一个一维数组有三个元素(int类型数据) 注意:一维数组中元素的个数可以是不同的 举例: int[][] arr = new int[][]{{1,2,3},{4,5},{6,7,8,9}}; 简化格式:数据类型[][] 变量名 = {{元素…},{元素…},{元素…},…}; 范例:int[][] arr = {{1,2,3},{4,5,6},{7,8,9}}; 动态初始化: 格式:数据类型[][] 变量名 = new 数据类型[m][n]; 范例:int[][] arr = new int[2][3]; 解读 定义了一个二维数组 二维数组中有2个元素(一维数组) 每一个一维数组有3个元素(int类型数据)
二维数组元素访问:
获取二维数组:数组名
获取每一个一维数组:数组名[索引]
获取每一个二维数组元素:数组名[索引][索引]
二维数组内存图:
继承
继承是面向对象三大特征之一(封装,继承和多态),主要作用之一是提高了代码的复用性
可以使得子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法
主要通过extends
关键字实现继承
继承的格式:
格式:public class 子类名 extends 父类名 { } 范例:public class Zi extends Fu { } Fu:是父类,也被称为基类、超类 Zi:是子类,也被称为派生类
示例:
项目结构如下图
定义父类FatherClass
package com.tencent.member; public class FatherClass { public FatherClass() {}; public void printHello() { System.out.println("Hello World"); } public String desc = "这是继承示例"; }
定义子类SonClass并继承父类FatherClass,在构造函数中调用父类中的方法
package com.tencent.member; public class SonClass extends FatherClass { public SonClass() { this.printHello(); System.out.println(this.desc); } }
定义ExtendsDemo类并创建SonClass的实例对象
package com.tencent.testDemo; import com.tencent.member.SonClass; public class ExtendsDemo { public static void main(String[] args) { SonClass son = new SonClass(); } }
子类SonClass调用父类FatherClass方法成功
集合
- 集合是基于数组实现的
- 集合常用api
2.1 ArrayList的构造方法和添加方法
public ArrayList() | 创建一个空的集合对象 |
public boolean add(E e) | 将指定的元素追加到此集合的末尾 |
public void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
- 2.2 ArrayList类常用方法【应用】
public boolean remove(Object o) | 删除指定的元素,返回删除是否成功 |
public E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
public E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
public E get(int index) | 返回指定索引处的元素 |
public int size() | 返回集合中的元素的个数 |
- 案例:
Student.java;
package com.tencent.member; import java.util.Scanner; // Scanner是java.util下的类,因此需要引入 public class Student { private String name; // 定义成员变量 private int age; // 定义成员变量 public Student() { // 定义构造方法 Scanner sc = new Scanner(System.in); // 创建键盘录入数据对象,读取键盘输入的数据。(通过System.in获取输入流,通过Scanner获取键盘输入流并解析出字符串。) // System是java.long下的类,因此不需要引入 // Scanner是java.util下的类,因此需要引入 System.out.println("请输入姓名"); this.name = sc.next(); // 通过键盘录入数据对象调用nextInt()方法获取字符串 System.out.println("请输入年龄"); this.age = sc.nextInt(); // 通过键盘录入数据对象调用nextInt()方法获取整数 } public void printInfo() { // 定义成员方法 System.out.println("姓名" + name + "年龄" + age); } }
- ListDemo
package com.tencent.testDemo; import com.tencent.member.Student; // 引入Student import java.util.ArrayList; public class ListDemo { public static void main(String[] args) { // 创建集合 ArrayList<Student> stuArr = new ArrayList<Student>(); // 新增元素 add for (int i = 0; i < 5; i++) { Student obj = new Student(); // 创建Student实例 stuArr.add(obj); } // 删除元素 remove stuArr.remove(1); // 修改元素 set Student newStu = new Student(); stuArr.set(0, newStu); // 遍历集合,获取集合长度以及集合元素 size get for (int i = 0; i < stuArr.size(); i++) { Student stu = stuArr.get(i); // 创建Student实例 stu.printInfo(); } } }