1.内部类(局部和匿名)
书写位置:在成员方法的位置中书写的类即使局部内部类。
局部内部类可以访问外部类的成员变量,包括私有成员。
在外部类访问局部位置,访问内部类的成员方法,则需要在外部类中创建内部类对象,进而对内部类对象来访问。
//定义一个外部类
class Outer{
public int num = 100 ;
private int num2 = 200 ;
//成员方法
public void method(){
//局部位置:局部内部类
class Inner{
//局部内部类的一个成员方法
public void show(){
System.out.println(num);
System.out.println(num2);
}
}
//创建局部内部类对象
Inner inner = new Inner() ;
inner.show() ;
}
}
//测试类
public class OuterDemo {
public static void main(String[] args) {
//访问方式:直接创建外部类类对象
//调用的成员方法
Outer outer = new Outer() ;
outer.method();
}
}
面试题
局部内部类访问局部变量的时候,此时局部变量应该注意什么?(JDK7/JDK8),为什么要加入final关键字呢?
此时Java环境是Jdk7,局部内部类访问局部变量时,此时该变量必须显示加入final修饰
目前环境是JDK8环境,做了什么优化?
通过反编译查看。没有反编译工具的无需担心,看下面代码,理解即可。
class Outer2{
public void method(){
int num = 20 ; //局部变量
class Inner2{
public void show(){
System.out.println(num);
}
}
//创建Inner2类对象
Inner2 inner2 = new Inner2() ;
inner2.show();
}
}
//测试类
public class OuterDemo2 {
public static void main(String[] args) {
//创建Outer2对象
Outer2 outer2 = new Outer2() ;
outer2.method();
}
}
//反编译
class Outer2$1Inner2{
final int val$num; //num已经加入了final修饰
final Outer2 this$0;
public void show()
{
System.out.println(val$num);
}
Outer2$1Inner2()
{
this.this$0 = this$0;
val$num = I.this;
super();
}
}
原因:
局部变量的生命周期是随着方法调用而存在,随着方法调用结束而消失,而当前外部类对象调用method 方法的时候,此时num进入栈内存,在局部位置创建了局部内部类对象。而局部内部类对象调用它的成员方法访问该变量,方法method方法结束之后,内部类对象不会立即消失, 它里面的成员方法在访问局部变量,局部变量必须变成常量,常驻内存,否则如果当前变量消失了,局部内部类的成员依然在访问就会出现冲突! 所以 jdk7 收到必须加入final修饰,jdk8通过jvm已经做了优化了,无需手动加入final修饰。
匿名内部类
简而言之,即没有名字的内部类,一般在局部位置使用。它是内部类的一种简化格式。
格式:new 类名(抽象/具体类/接口) (){
重写功能;
};
本质:继承了该类或者实现了该接口的子类对象
//定义一个接口
interface Inter{
void show() ; //public abstract修饰 (可以省略)
void show2() ;
}
/*class InterImpl implements Inter{
@Override
public void show() {
}
@Override
public void show2() {
}
}*/
//外部类
class Outer3{
//定义一个成员方法
public void method(){
// class Inner3{} 有名字内部类
//使用匿名内部类去写
/*
new 类名(可以是抽象类,也可以具体类)或者是接口名(){
重写功能
} ;
*/
//情况1:接口中只有一个方法
/* new Inter(){ //接口名
@Override
public void show() {
System.out.println("show Inter...");
}
}.show() ;*/
//情况2:接口中有两个方法
/* new Inter(){
@Override
public void show() {
System.out.println("show Inter...");
}
@Override
public void show2() {
System.out.println("show2 Inter...");
}
}.show() ;
new Inter(){
@Override
public void show() {
System.out.println("show Inter...");
}
@Override
public void show2() {
System.out.println("show2 Inter...");
}
}.show2() ;*/
//优化:给匿名内部类起一个名字
Inter i = new Inter(){
@Override
public void show() {
System.out.println("show Inter...");
}
@Override
public void show2() {
System.out.println("show2 Inter...");
}
};
i.show();
i.show2();
}
}
//测试类
public class OuterDemo3 {
public static void main(String[] args) {
//创建Outer3类对象
Outer3 outer3 = new Outer3() ;
outer3.method();
}
}
应用场景
1.方法的形式参数如果是一个接口,实际需要传递的接口子实现类对象
方式1:将接口的子实现类定义出来
方式2:使用接口的匿名内部类(可以降低数据间的耦合性)
example1
//定义一个结婚的接口
interface Mary{
void mary() ;
}
//定义一个LoveDemo类
class LoveDemo{
public void funciton(Mary mary){//形式参数是一个接口
mary.mary();
}
}
//定义一个子类实现类
class You implements Mary{
@Override
public void mary() {
System.out.println("要结婚了,很开心...");
}
}
//测试类
public class LoveTest {
public static void main(String[] args) {
//方式1:需要调用LoveDemo类中的function方法
LoveDemo loveDemo = new LoveDemo() ; //或者使用匿名对象
//接口多态
Mary mary = new You() ;
loveDemo.funciton(mary);
System.out.println("----------------------------------------");
//方式2:接口的匿名内部类
//创建LoveDemo类对象
LoveDemo ld = new LoveDemo() ;
ld.funciton(new Mary() {
@Override
public void mary() {
System.out.println("要结婚了,很开心...");
}
});
}
}
example2
//抽象类
abstract class Person{
public abstract void work() ;
}
//PersonDemo类
class PersonDemo{
public void method(Person p){//方法的形式参数是一个抽象类
p.work();
}
}
//定义一个子类继承自Person类
class Student extends Person{
@Override
public void work() {
System.out.println("good good study ,day day up!!");
}
}
//测试类
public class PersonTest {
public static void main(String[] args) {
//调用PersonDemo类中的method方法?
//创建PersonDemo类对象 /或者匿名对象
PersonDemo pd = new PersonDemo() ;
//抽象类多态:创建子类对象
Person p = new Student() ; //定义一个子类Student
pd.method(p) ;
System.out.println("----------------------------------------");
//使用匿名内部类去完成:
/**
* new 类名(抽象类)/接口名(){
* 重写方法
* } ;
*/
//调用PersonDemo类中的method方法?
PersonDemo pd2 = new PersonDemo() ;
pd2.method(new Person(){ //实际参数也是传递抽象类的子类对象(抽象类的匿名内部类)
@Override
public void work() {
System.out.println("good good Study,day day Up!!");
}
});
}
}
2.方法的返回值是接口类型,需要返回的当前接口的子实现类对象
example1
interface Love{
void love() ;
}
class LoveDemo{
public Love function(){
//return ?
//通过接口多态
//Love love = new Student() ;
//return love ;
//匿名对象
// return new Student() ;
//使用接口的匿名内部类
/**
* new 类名/接口名(){
*
* 重写方法
* } ;
*/
return new Love(){
@Override
public void love() {
System.out.println("爱Java,爱学习...");
}
} ;
}
}
//定义接口的子实现类
class Student implements Love{
@Override
public void love() {
System.out.println("爱Java,爱学习...");
}
}
//测试类
public class LoveTest {
public static void main(String[] args) {
//要访问LoveDemo类中的function方法
LoveDemo ld = new LoveDemo() ;
Love love = ld.function();//Love love = new Student() ;
love.love();
System.out.println("------------------");
//方式2:接口匿名内部类的方式
LoveDemo ld2 = new LoveDemo() ;
Love l = ld2.function();
l.love();
}
}
example2
abstract class Person{
public abstract void work() ;
}
class PersonDemo{
public Person method(){
//return ?
//抽象类多态
// Person person = new Programmer() ;
// return person ;
// return new Programmer() ;
//直接抽象类的匿名内部类
return new Person(){//相当于Person类的子类对象(匿名内部类的本质)
@Override
public void work() {
System.out.println("程序员日日夜夜敲代码");
}
} ;
}
}
//定义一个子类
class Programmer extends Person{
@Override
public void work() {
System.out.println("程序员日日夜夜敲代码...");
}
}
//测试类
public class PersonTest {
public static void main(String[] args) {
//调用PersonDemo类中的method 方法
PersonDemo pd = new PersonDemo() ;
Person person = pd.method(); //Person pserson = new Programmer() ;
person.work();
System.out.println("--------------------------");
//方式2:匿名内部类
PersonDemo pd2 = new PersonDemo() ;
Person p = pd2.method();
p.work();
}
}
看程序写结果
要求:需要在控制台分别打印30,20,10
class Outer{
int num = 10 ;
//成员内部类
class Inner{
int num = 20 ;
public void show(){
int num = 30;
//补全代码
System.out.println(num);
System.out.println(this.num);//this限定 :this.变量名:当前类的成员变量
// System.out.println(new Outer().num) ; //方式1:new Outer().num
System.out.println(Outer.this.num) ; //方式2:外部类的this限定
}
}
}
public class OuterTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner() ;
oi.show();
}
}
考点:
- 外部类直接访问非静态的成员内部类的格式
- 外部类的成员变量的方法方式,(在成员内部类的成员方法中)
- 成员变量,局部变量名称都一样(就近原则)
- 外部类和内部类没有继承关系
2.常用类(Object)
1.Object
java.lang.Object:是类结构层次的根类(超类—>父类),所有的类都默认继承自Object子类(派生类)
通过jdk提供的API文档学习常用类(其余类也一样)
API:Application Programming Interface:应用程序接口开发文档
1)getClass()方法(public final Class getClass())
获取正在运行的类(就是字节码文件对象),在getClass()方法后可以继续跟getName()获取当前类的 全限定名称(包名.类名)。public String getName():返回一个字符串。
2)hashCode()方法(public int hashCode())
获取对象的一个哈希码值 (本质不是地址值,可以把它理解为地址值)----跟哈希表有关系(HashMap)
一般情况:不同的对象获取的哈希码值是不同的 ,(但是中文字符,可能内容不一样,但是哈希码值不同!)
底层是通过哈希表算出来的,目前先了解!
底层代码中的native关键字:本地方法,指非java语言底层实现。c/c++。
public class Student {
public static void get(){
System.out.println("get student");
}
}
public class ObjectDemo {
public static void main(String[] args) throws ClassNotFoundException {
//创建一个学生类对象
Student s = new Student() ;
Class c1 = s.getClass();
System.out.println(c1);//class com.qf.generator_class_05.Student class 包.类名
Class c2 = s.getClass();
System.out.println(c2);//class com.qf.generator_class_05.Student class 包名.类名
System.out.println(c1 == c2);
//==在基本数据类型里面:比较的是数据值相同,在引用类型:比较的是两个对象的地址值是否相同
//Student.class---->就加载一次
System.out.println("---------------------------------");
Student s2 = new Student() ;
System.out.println(s == s2);//false :两个对象
System.out.println("----------------------------------");
//获取c1/c2 所代表的类 的全限定名称
// Class ---->class com.qf.generator_class_05.Student
String name1 = c1.getName();
String name2 = c2.getName();
System.out.println(name1);
System.out.println(name2);
System.out.println("--------------------------------");
//Class类中public static Class forName(String classname): 后期反射中使用
Class c3 = Class.forName("com.qf.generator_class_05.Student");
System.out.println(c1==c3);
System.out.println(c2==c3);
System.out.println("--------------------------------");
Class c4 = Student.class ; //任意Java类型的class属性----获取当前类的字节码文件对象Class
System.out.println(c4);
System.out.println(c1==c4);
System.out.println(c2==c4);
System.out.println(c3==c4);
System.out.println("---------------------------------------");
//创建两个对象
// public int hashCode()
Student s3 = new Student() ;
Student s4 = new Student() ;
System.out.println(s3.hashCode());
System.out.println(s4.hashCode());
System.out.println("helloworld".hashCode());
System.out.println("javaee".hashCode());
System.out.println("helloWorld".hashCode());
System.out.println("helloworld".hashCode());
}
}
面试题: 获取一个类的字节码文件对象有几种方式?
三种:
第一种:通过Object类的getClass()—>Class :正在运行的java类: class 包名.类名
第二种:任意Java类型的class属性----获取当前类的字节码文件对象Class
第三种方式:Class里面forName(“类的全限定名称(包名.类名)”) ; (使用最多)
3)toString()方法 (public String toString())
返回对象的字符串表示形式。结果应该是一个简明扼要的表达,容易让人阅读。
建议所有子类覆盖此方法。
描述一个对象:是由很多属性(成员变量组成),应该看到的具体的属性描述
也可以直接快捷键----重写toString即可(大部分的常用类或者后面的集合都会重写Object类的toString())
public class Student extends Object {
String name ;
int age ;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//手动重写Object的toString
/* @Override
public String toString() {
return "姓名是"+name+",年龄是"+age;
}*/
//alt+ins--->toString()即可
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';//描述学生对象的成员信息表达式
}
}
public class ObjectDemo {
public static void main(String[] args) {
//通过有参构造方法创建一个学生对象
Student s = new Student("高圆圆",42) ;
//直接输出对象名称 --->会默认调用它的父类:Object的toString方法
System.out.println(s);//com.qf.object_06.Student@1540e19d
System.out.println("-----------------------------------");
/**
* Object类的toString方法的原码
* public String toString() {
* return getClass().getName() + "@" + Integer.toHexString(hashCode());
* }
*
* Integer类:int类型的包装类类型
* public static String toHexString(int i) :将整数转换成16进制数据--结果以String类型展示
*/
/*System.out.println(s.getClass().getName()+"@"+Integer.toHexString(s.hashCode()));
System.out.println(s.toString());*/
System.out.println(s.toString());
/*String str = new String("hello") ;
System.out.println(str);*/
}
}
4)equals()方法(public boolean equals(Object obj))
判断当前obj对象是否和当前对象相等
面试题:equals和==的区别?
==: 连接的基本数据类型:比较的是数据值否相同
==: 连接的是引用类型,比较的是地址值是否相同
equals方法:如果使用Object默认的:底层用==,默认比较的还是两个对象的地址值是否相同
例:Student s1 = new Student(“文章”,35) ;
Student s2 = new Student(“文章”,35) ;
s1和s2虽然地址值不同,他们的成员的内容相同,认为他是同一个人,但是如何让s1.equals(s2)为true:针对equals来说比较的是成员信息内容是否相同;
String重写Object的equals方法同时还需要重写hashCode
内容相同,还需要比较哈希码值相同
alt+ins—>hashcode+equals方法
重写之后,就比较的是成员信息的内容是否相同!
public class Student {
String name ;
int age ;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//重写Object类的toString
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写了equals和code方法
//首先比较:s1和s2它的哈希码值是否相同
@Override
public int hashCode() {
int result = name.hashCode();//name:String "文章".hashCode() ; 837177
result = 31 * result + age; //31 * 837177 + 35
return result; //得到一个结果
}
//比较完哈希码值之后,然后还要确定一下成员内容是否都一样(名字----"中文字符")
//s1.equals(s2)
@Override
public boolean equals(Object o) { //Object o = new Student() ; Student s2 = new Student() ;
if (this == o) return true; //if(this==o){//如果当前s1对象和s2对象地址值相同
//return true ;
// }
if (o == null || getClass() != o.getClass()) return false;
//如果s2对象为null或者是当前s1.getClass() 和s2.getClass() 字节码文件对象不相同,直接返回false
Student student = (Student) o; //向下转型: o--->Student student
if (age != student.age) return false; //判断年龄是否相同(s1) this.age !=student.age (s2)
return name.equals(student.name); //姓名是一个:String
//s1.name.equals(s2.name) ;
//String类型 本身底层已经重写了Object类的equals方法,所以 直接比较的是字符串的内容是否相同
}
}
public class ObjectDemo {
public static void main(String[] args) {
//==
int a = 10 ;
int b = 15 ;
System.out.println(a==b);//==链接的基本数据类型:比较的是数据值否相同
System.out.println("--------------------------------------------");
Student s1 = new Student("文章",35) ;
System.out.println(s1);
Student s2 = new Student("文章",35) ;
System.out.println(s2);
System.out.println(s1 == s2);
System.out.println("--------------------------------------");
//public boolean equals(Object obj)//Object obj = new Student() ;多态
System.out.println(s1.equals(s2));
//没有重写之前:执行的是Object类的equals()
//重写之后,就比较的是对象的成员信息是否一致!
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println("文章".hashCode());
/***
*Object类中的equals的源码
* public boolean equals(Object obj) { //s1 ---this obj---->s2
* return (this == obj); return s1 == s2 ; ==:引用类型:比较的是地址值是否相同
* }
*/
System.out.println("---------------------------------------------");
// String类型(大部分常用类都会重写equals)重写Object的equals方法,所以比较内容是否相同
String str1 = "hello" ;
String str2 = "hello" ;
System.out.println(str1.equals(str2));
String str3 = "world" ;
String str4 = new String("world") ;
System.out.println(str3.equals(str4));
}
}
5)clone()方法(克隆)(protected Object clone() throws CloneNotSupportedException:创建对象并返回该对象的副本)
这个方法会抛出一个异常,throws:表示的是可能出现异常,针对调用者必须进行处理
要使用clone方法,当前进行克隆的对象所在的类必须实现"标记接口"Cloneable,在实现这个接口之后就可以使用Object的clone()方法了。
标记接口指的是既没有字段(成员变量),也没有成员方法
clone()克隆指的是浅克隆,浅克隆就是将被克隆的对象的地址值赋值给接受地址。作用与传统方式无异。
//学生类
public class Student implements Cloneable{
private String name ;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//测试类
public class ObjectDemo {
public static void main(String[] args) throws CloneNotSupportedException{
//创建学生对象
Student s1 = new Student("高圆圆",42) ;
System.out.println(s1);
System.out.println(s1.getName()+"---"+s1.getAge());
System.out.println("-----------------------------------");
//调用克隆方法clone()
Object obj = s1.clone(); //已经克隆了(浅克隆:将s1地址值赋值给Objet)
//向下转型
Student s2 = (Student) obj;
System.out.println(s2);
System.out.println(s2.getName()+"---"+s2.getAge());
System.out.println("-----------------------------------");
//传统方式
Student s3 = s1 ;
System.out.println(s3.getName()+"---"+s3.getAge());
}
}
3.Scanner类提供的判断功能
Scanner类:文本扫描器
使用前需要导入包:java.util.Scaner ;
Scanner的构造方法:public Scanner(InputStream source):创建一个文本扫描器
形式参数是一个抽象类,它通过System类里面的public static final InputStream in成员
System类里面的public static final InputStream in = null;
本地方法(非Java语言实现)—> private static native void setIn0(InputStream in);
native表示本地的:表明底层方法一定会创建系统资源来读取用户输入的 字符(整数,字 符串…)(非java语言实现,不用纠结)
Scanner提供判断功能是为了防止输入的类型和结果不匹配。
public boolean hasNextXXX():判断下一个录入的是否为指定的XXX类型
XXX nextXXX() 获取功能
如: public boolean hasNextInt()用于判断输入是否为整型
int nextInt()
在我们输入接受字符串时出现一个问题:如果先录入int,在录入String用户(nextLine()接收)。 录入的字符串数据就会被漏掉。
解决方案:
1)直接使用next()---->String
2)在使用nextLine()之前,在创建Scanner对象即可
public class ScannerDemo {
public static void main(String[] args) {
//创建键盘录入对象
InputStream inputStream = System.in ; //标准输入流 IO(Input 读 ,Output 写) :Java高级特性:IO
Scanner sc = new Scanner(inputStream) ;// public Scanner(InputStream source) :创建一个文本扫描器
System.out.println("请您输入一个数据:");
if(sc.hasNextInt()){
int num = sc.nextInt() ;
System.out.println("您录入的数据是:"+num);
}else if(sc.hasNextLine()){
//录入的字符串
String line = sc.nextLine() ;
System.out.println("您录入的数据是:"+line);
}else{
System.out.println("您录入的数据和结果类型不匹配...");
}
//录入数据
// int num = sc.nextInt(); //java.util.InputMismatchException
// System.out.println("您要录入的数据是:"+num);
}
}
4.常用类(String)
字符串是一个常量,一旦被赋值了,其值(地址值)不能被更改
推荐的使用方式: String 变量名 = “xxxx” ;//xxxx代表 的当前String的实例
因为String 变量名 = new String()会在堆内存中开辟空间,然后检索字符串常量池,造成了空间浪费。而静态定义直接检索常量池即可,不存在则创建。二者作用相同,所以用静态即可!!!
String的构造方法:
-
public String():空参构造:空字符序列
-
public String(byte[] bytes):将一个字节数组构造成一个字符串,使用平台默认的字符集(utf-8:一个中文对应三个字节) 解码
-
编码和解码—保证字符集统一
-
编码:将一个能看懂的字符串---->字节 “今天老地方见” utf-8
-
解码:将看不懂的字节---->字符串 “今天老地方见” gbk
-
public String(byte[] bytes,字符集):使用指定的字符集,将字节数组构造成一个字符串
-
public String(byte[] bytes,int offset,int length):将指定的部分字节数组转换成字符串
-
参数1:字节数组对象,参数2:指定的角标值 参数3:指定长度
-
public String(char[] value):将字符数组构造成一字符串
-
public String(char[] value,int offset,int count):将部分字符数组转换成字符串
-
public String(String original):构造一个字符串,参数为字符串常量
public class StringDemo {
public static void main(String[] args) {
//测试
String s = new String() ;
System.out.println("s:"+s); //String类重写了Object的toString(),
System.out.println(s.length());
System.out.println("-------------------------------------------");
byte[] bytes = {97,98,99,100,101} ;
// public String(byte[] bytes)
String s2 = new String(bytes) ;
System.out.println(s2);
System.out.println(s2.length());
System.out.println("-------------------------------------------");
//public String(byte[] bytes,int offset,int length):
String s3 = new String(bytes,2,2) ;
System.out.println(s3);
System.out.println(s3.length());
System.out.println("-------------------------------------------");
//public String(char[] value)
char[] chs = {'我','爱','高','圆','圆'} ;
String s4 = new String(chs) ;
System.out.println(s4);
System.out.println(s4.length());
System.out.println("-------------------------------------------");
// public String(char[] value,int offset,int count)
String s5 = new String(chs,1,4) ;
System.out.println(s5);
System.out.println(s5.length());
System.out.println("---------------------------------------------");
// public String(String original)
String s6 = new String("hello") ; //创建字符串对象,常量值:hello
System.out.println(s6);
String s7 = "hello" ; //推荐的方式
System.out.println(s7);
}
}
1.常用功能
1.1 int length():获取字符串长度。
面试题:在数组中有没有length方法,在String类中有没有length方法,在集合中有没有length方法?
数组中没有length方法,length属性;String类中有length(); 集合中没有length(),通过size()获取元素数
面试题:String s1 = “hello” ;String s2 = new String(“hello”) ;在内存中分别创建了几个对象?
第一个创建了一个对象,直接在常量池创建,开辟常量池空间。
第二个:创建了两个对象,一个堆内存中开辟空间,一个指向常量池(不推荐)
1.2 == 和equals:
==:连接基本数据类型,比较的是值;连接引用类型比较的是地址
equals():比较两个字符串的内容(默认比较地址值,String对equals进行了重写)
1.3常用的转换功能(重点)
byte[] getBytes() :将字符串转换成字节数组 (编码)。字符串—>看不懂的字节数
如果方法为空参,使用平台默认的编码集进行编码(utf-8:一个中文对应三个字节)
byte[] getBytes(String charset):使用指定的字符集进行编码
解码的过程:将看不懂的字节数----->String
String(byte[] bytes):使用默认字符集进行解码
String(byte[] bytes,指定字符集)
编码和解码必须要保证字符集统一,否则将产生错误,解码后既然看不懂
字符集:
-
gbk :一个中文两个字节(中国中文编码表)
-
gb2312:gbk升级版(含义有一个中文字符:中国的中文编码表)
-
iso-8859-1:拉丁文码表
-
utf-8:任何的浏览器—>都支持 utf-8格式 (后期统一个)
-
unicode:国际编码表
-
JS:日本国际 电脑系统 一个字符集
1.4 public static String toString(int/byte/float/double…[] a):将任意类型的数组---->String
1.5 public char[] toCharArray():将字符串转换成字符数组、
1.6 public String toString():返回自己本身—"当前字符串的内容"
1.7 public String toUpperCase():将字符串转换成大写
1.8 public String toLowerCase():将字符串转换成小写
1.9 public boolean equals(Object anObject):比较两个字符的内容是否相同 (区分大小写)
1.10 public boolean equalsIgnoreCase(String anotherString):比较两个字符串是否相同(不区分大小写)
1.11 public boolean startsWith(String prefix):判断字符串是否以指定的内容开头
1.12 public boolean endsWith(String suffix):判断字符串是否以指定的内容结尾
1.13 boolean isEmpty() 判断字符串是否为空 :若为空,则返回true;否则返回false
String s = “” ;// 空字符串 ,存在String对象 ""
String s = null ; 空值 (空对象) null:引用类型的默认值
1.14 public char charAt(int index) 返回字符串中的第index个字符
1.15 public String concat(String str):将指定的字符串和当前字符串进行拼接,获取一个新的字符串
1.16 public String[] split(String regex):拆分功能:通过指定的格式将字符串—拆分字符串数组
1.17 public String substring(int beginIndex) :从指定位置开始默认截取到末尾(角标从0开始)
1.18 public String substring(int beginIndex,int endIndex):从指定位置开始,截取到位置结束(左闭右开区间,也就是包左不包右)
1.19 public static String valueOf(boolean/int/long/float/double/char…Object b)
万能方法,将任意类型转换String类型
1.20 public String replace(char target,char replacement):替换功能 将指定的内容使用target字符进行替换
1.21 public String replaceAll(String regex, String replacement) : 将指定的和参数1正则表达式匹配的字符串 使用replacement进行替换
1.22 public String trim():去除字符串两端的空格
1.23 (重点)public int compareTo(String anotherString):按照字典顺序比较,返回值是int。
比较规则是先比较字符串对应位置的字符,如果字符相等,则长度相减。
String s1 = "hello" ; "abc" String s2 = "hel" ; "hello" s1.compareTo(s2) ; class String{ private final char value[];//value属性 //按照字典顺序比较 public int compareTo(String anotherString) { //s2 int len1 = value.length; //计算第一个字符数组的长度 int len2 = anotherString.value.length; int lim = Math.min(len1, len2); //Math.min(5,3) ---->lim = 3 char v1[] = value; //char v1[] = s1.value= {'h','e','l','l','o'} char v2[] = anotherString.value;//char v2[] = s2.value = {'h','e','l'} int k = 0; //统计变量k = 0 while (k < lim) { 0 < 3 1< 3 2< 3 3< 3(不成立) char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { //如果不相等则差值输出 return c1 - c2; } k++; //k=1 2 3 } //最短字符串比较结束,则长度相减len1 - len2 = 5 -3 = 2 return len1 - len2; } }
public class StringDemo2 { public static void main(String[] args) { String s = "helloworld" ; System.out.println("replace():"+s.replace('l','k')); System.out.println("-------------------------------------"); //public String trim():去除字符串两端的空格 String s2 = "hello"; System.out.println("s2:"+s2+"----"); String s3 = " hello " ; System.out.println("s3:"+s3); System.out.println("s3:"+s3.trim()+"----"); System.out.println("------------------------------------"); // public int compareTo(String anotherString):按照字典顺序比较,返回值是int String str1 = "abc" ;//字典顺序:就是我们26个字母,a,b,c,d,e,f,g,h String str2 = "hello" ; System.out.println(str1.compareTo(str2)); String str3 = "hel" ; System.out.println(str2.compareTo(str3)); /** * 面试题 * String s1 = "hello" ; * String s2 = "hel" ; * * 使用s1调用compareTo(s2):按照字典顺序比较:结果是多少? * 是怎么运行的? 长度相减 * */ }
2.StringBuffer
StringBuffer:字符串缓冲区 ,类似于String。但是不一样 (它可变的字符序列)
且StringBuffer是线程安全的(同步),执行效率低即多线程时不能同时访问资源。
StringBuilder : 和StringBuffer具有相互兼容的API,它是线程不安全的类(不同步),执行效率高。单线程时都采用StringBuilder,因为不存在资源抢占,表现在不会有另一个线程同时访问一个变量,造成计算或事件结果与事实不符。它此时也是线程安全的。
2.1StringBuffer的构造方法
2.1.1 public StringBuffer() :空参构造,创建一个空字符序列的字符串缓冲区 (推荐)
2.1.2 public StringBuffer(int capacity):构造一个字符串缓冲区对象,指定容量大小
2.1.3 public StringBuffer(String str):指定字符序列,长度加上初始容量16(总容量)
public class StringBufferDemo {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer() ;
System.out.println("sb:"+sb); //空字符序列;重写Object的toString()
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println("------------------------------");
StringBuffer sb2 = new StringBuffer(20) ;
/**
* 内部实现---->调用父类的构造函数: 相当于内部创建了一个字符数组对象
* AbstractStringBuilder(int capacity) {
* value = new char[capacity];
* }
*/
System.out.println("sb2:"+sb2);
System.out.println(sb2.length());
System.out.println(sb2.capacity());
System.out.println("------------------------------");
StringBuffer sb3 = new StringBuffer("hello") ; //'h','e','l','l','o'
System.out.println("sb3:"+sb3);
System.out.println(sb3.length());
System.out.println(sb3.capacity());
}
}
2.2 StringBuffer的获取功能
2.2.1 public int length():获取字符数(长度)
2.2.2 public int capacity():获取字符串缓冲区容量
2.3 StringBuffer的添加功能
2.3.1 StringBuffer append(任何类型) :将内容追加到字符串缓冲区中 (在字符串缓冲区的最后一个字符序列的末尾追加)
2.3.2 public StringBuffer insert(int offset,String str):插入:在指定位置处插入指定的内容
2.4 StringBuffer的删除功能
2.4.1 public StringBuffer deleteCharAt(int index):删除指定索引处的缓冲区的字符序列,返回字符串缓冲区本身
2.4.2 public StringBuffer delete(int start,int end):删除从指定位置到指定位置结束的字符序列(包含end-1处的字符),返回字符串缓冲区本身
2.5 StringBuffer的截取功能
2.5.1 public String substring(int start):从指定位置开始,默认截取到末尾,返回值是新的字符串
2.5.2 public String substring(int start,int end):从指定位置开始到指定end-1结束进行截取,返回的新的字符串
2.6 StringBuffer的替换功能
public StringBuffer replace(int start(起始索引),int end结束索引(end-1), String str(替换的内容) )
public class StringBufferDemo5 {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer() ;
sb.append("hello").append("world").append("javaee").append("anroid") ;
System.out.println("sb:"+sb);
// System.out.println(sb.substring(5));//subString(xx)---->截取的新的字符串
//System.out.println("sb:"+sb);
// System.out.println(sb.substring(5,10));//end-1位置
System.out.println("------------------------------------");
//public StringBuffer replace(int start, 起始索引
// int end, 结束索引(end-1)
// String str) 替换的内容
System.out.println(sb.replace(5,10,"高圆圆"));
}
}
2.7 StringBuffer的特有功能
public StringBuffer reverse(),反转之后,返回的是字符串缓冲区本身
public class StringBufferDemo4 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in) ;
//提示并录入
System.out.println("请您输入一个字符串:");
String line = sc.nextLine() ;
//需要用StringBuffer的特有功能 reverse
//line---->StringBuffer类型
StringBuffer sb = new StringBuffer(line) ;
String result = sb.reverse().toString();
System.out.println(result);
System.out.println("-----------------------------");
//调用功能
String result2 = reverse(line);
System.out.println(result2);
}
public static String reverse(String s){
//分步走
//方式1:s---->StringBuffer类型---->有参构造
//StringBuffer buffer = new StringBuffer(s) ;
//return buffer.reverse().toString() ;
//方式2:append()+空参构造方法
/*StringBuffer buffer = new StringBuffer() ;
String result = buffer.append(s).reverse().toString();
return result ;*/
//匿名对象
return new StringBuffer().append(s).reverse().toString() ;
}
}
3 类型的相互转换
String---->StringBuffer
StringBuffer---->String
简而言之就是通过各自的有参构造方法进行转换
public class StringBufferDemo3 {
public static void main(String[] args) {
//String---->StringBuffer
String s = "hello" ;
//错误的写法
// StringBuffer sb = s ;//两个类型不一致
//方式1:StringBuffer有参构造方法
StringBuffer sb = new StringBuffer(s) ;
System.out.println(sb);
System.out.println("---------------------------");
//方式2:StringBuffer的无参构造方法 结合append(String str)
StringBuffer sb2 = new StringBuffer() ;
sb2.append(s) ;//追加功能
System.out.println(sb2);
System.out.println("-------------------------------------------");
//StringBuffer---->String
//创建字符串缓冲区对象
StringBuffer buffer = new StringBuffer("helloJavaee") ;
//方式1:String类型的构造方法
//public String(StringBuffer buffer)
String str = new String(buffer) ;
System.out.println(str);
System.out.println("-------------------------------------------");
//方式2:StringBuffer的public String toString()方法
String str2 = buffer.toString();
System.out.println(str2);
}
}
4 面试题
4.1StringBuffer和数组的区别?
数组:只能存储同一种数据类型容器,数组可以存储基本类型,也可以存储引用类型。
数组的最大特点:长度固定。
StringBuffer:支持可变的字符序列,里面存储可以存储任意类型的元素。
append(int/char/double/float/Obejct/String)
isnert(int offert,int/char/double/float/Obejct/String)
一般情况:开发中 将StringBuffer----->String
4.2集合/数组的区别?
集合在为指定泛型的时候可以存储不同数据类型,但都是引用数据类型,底层用数组或链表完成功能。且长度可变。
数组只能存储一种数据类型,且长度不可变。
4.3 StringBuffer,StringBuilder和String的区别?
String:字符串是一个常量,一旦被赋值,其值不能更改/作为形式参数属于特殊的引用类型,形式参数的改变不会实际参数.
StringBuffer:可变的字符序列,线程安全的类----同步的----->执行效率低(线程角度)
StringBuilder:可变的字符序列.和StringBuffer具有相互兼容的api,单线程程序中(只考虑执行效率,不考虑安全问题)。
5.常用类(包装类(Integer、character…)
包装类是针对基本数据类型而言的,四类八种基本类型都有自己对应的引用类型。
其作用最主要体现在基本数据类型和String类型之间转换作为“中间桥梁”。
整数类型 引用类型(默认值都是null)
byte Byte
short Short
int Integer
long Long
浮点类型
float Float
double Double
字符类型
char Character
布尔类型
boolean Boolean
4.1 基本功能(以Integer为例)
4.1.1 public static String toBinaryString(int i):将整数---->二进制 的字符串
4.1.2 public static String toOctalString(int i):将整数---->八进制的字符串
4.1.3 public static String toHexString(int i):将整数---->十六进制数据
4.1.4 public static final int MAX_VALUE:int的最大值
4.1.5 public static final int MIN_VALUE:int的最小值
public class IntegerDemo {
public static void main(String[] args) {
System.out.println(Integer.toBinaryString(100));
System.out.println(Integer.toOctalString(100));
System.out.println(Integer.toHexString(100));
System.out.println("----------------------");
System.out.println(Integer.MIN_VALUE);//-2的31次方
System.out.println(Integer.MAX_VALUE);//2的31次方-1
}
}
4.1.6 构造方法
Integer(int value):可以将int类型保证为Integer类型
Integer(String s) throws NumberForamtException: 抛出一个数字格式化异常
注意事项:当前字符串如果不是能够解析的整数的,就会出现数字格式化异常,s必须为 数字字符串
public class IntegerDemo2 {
public static void main(String[] args) {
//创建Integer类对象
int i = 100 ;
Integer integer = new Integer(i) ;
System.out.println(integer);
System.out.println("---------------------");
//创建一个字符串
// String s = "hello" ;
String s = "50" ;
Integer integer2 = new Integer(s) ;
System.out.println(integer2);
}
}
4.2 JDK5 以后的新特性
自动拆装箱,可变参数,静态导入,增强for循环,<泛型>,枚举。
4.2.1自动拆装箱
简而言之,基本类型转换为对应的包装类类型 (装箱)。对应的包装类型转换为基本类型(拆箱)。
public class IntegerDemo3 {
public static void main(String[] args) {
//创建Integer类对象
int i = 100 ;
Integer ii = new Integer(i) ;
ii += 200 ;
System.out.println("ii:"+ii);
/**
*通过反编译工具查看
int i = 100;
Integer ii = new Integer(i); //创建Integer类对象
ii = Integer.valueOf(ii.intValue() + 200); ii = Integer.valueOf(先拆箱--Integer--->int + 200)
//将300赋值Integer变量ii,底层使用valueOf(int)--->int---->Integer 装箱
System.out.println((new StringBuilder()).append("ii:").append(ii).toString());//以字符串形式输出出来
*/
}
}
关于Integer的静态方法valueOf(),当int值在-128-127之间的时候,将其进行装箱时不会进行重新new空间对象,这部分的空间对象系统已经给出,会自动给Integer变量直接赋值。
也就是说,Integer i1 = new Integer(100);
Integer i2 = new Integer(100); 此时i1与i2的地址值是相同的。
4.2.2 静态导入(方法级别)
Math类的功能都是静态的,就可以使用静态导入
import static 包名.类名.方法名; 但是前提是不能和其他方法同名
如:import static java.lang.Math.abs ;
import static java.lang.Math.random;
此时直接用方法名使用即可
4.2.3 增强for循环
增强for循环和for循环没有关系!
增强for循环底层仍然是借助迭代器来实现的
格式 for (数据类型 变量名:集合 ){
循环题;//后面集合遍历有使用
}
4.2.4 泛型
泛型的格式 : <引用数据类型>,在进行集合创建的时候,声明其引用类型,则当前集合当中便只能存储当前声明的类型数据。
集合类型<引用数据类型> 集合对象名 = new 子实现类<引用数据类型>() ;
泛型的好处:
1)将运行时期异常提前了编译时期
2)避免了强制类型转换
3)提高了程序安全性
4.2.5 枚举
简而言之,就是存储一系列常量的类似于类的结构
格式 enum {
元素1 ;元素2;元素3;…
}
4.3 int与String之间的相互转化
int转换为String:
方式1:直接使用字符串拼接 String = String + int;
方式2:Integer的静态功能 public static String toString(int i);
String s = Integer.toString(i);
方式3:int---->Integer---->public String toString(),此时可以看出来底层也是用的toString静态方法
String转换为int:
方式1:public static int parseInt(String s)throws NumberFormatException:数字字符串 (使用最多) int result = Integer.parseInt(s);
方式2:String ---->Integer---->int。也就是先Integer的构造方法 Integer(String s)生成对象 Integer integer = new Integer(s) ;然后用对象的成员方法intValue() int result2 = integer.intValue()。
public class IntegerDemo4 {
public static void main(String[] args) {
//int---->String
int i = 50 ;
//String result = "" ;
//result = result + i ;//拼接符号
//System.out.println(result);//"50"
//使用功能
//方式1: Integer类的静态功能
//public static String toString(int i)
String str = Integer.toString(i);
System.out.println(str);
System.out.println("------------------------");
//方式2:int---->Integer---->public String toString()
Integer ii = new Integer(i) ;
String str2 = ii.toString(); //底层使用的方法public static String toString(int i)
System.out.println(str2);
System.out.println("----------------------------------");
//String--->int(使用居多)
//开发中:浏览器(客户端)---->传递给后端的数据(String类型)
//方式1:public static int parseInt(String s)throws NumberFormatException:数字字符串 (使用最多)
//通用方法:String--->long Long.parseLong(String s)---->long
// String ----double Double public static double parseDouble(String s)
String s = "100" ;
int result = Integer.parseInt(s);
System.out.println(result);
System.out.println("------------------------------------------");
//String ---->Integer---->int
//Integer的构造方法 Integer(String s)
//Integer 的成员方法:int intValue()--->int
Integer integer = new Integer(s) ;
int result2 = integer.intValue();
System.out.println(result2);
}
}
4.4 Character
char类型的包装类类型
构造方法:public Character(char value)
主要功能:
public static boolean isUpperCase(char ch):判断当前字符是否大写字母字符
public static boolean isLowerCAse(char ch):是否为小写字母字符
public static boolean isDigit(char ch):是否为数字字符
public static char toLowerCase(char ch):将字符转换成小写
public static char toUpperCase(char ch):将字符转换成大写
public class CharacterDemo {
public static void main(String[] args) {
//创建字符类对象
Character character = new Character('a') ;
// Character character = new Character((char)(97)) ;
System.out.println(character);
System.out.println("---------------------------------");
System.out.println("isUpperCase():"+Character.isUpperCase('A'));
System.out.println("isUpperCase():"+Character.isUpperCase('a'));
System.out.println("isUpperCase():"+Character.isUpperCase('0'));
System.out.println("---------------------------------");
System.out.println("isLowerCase():"+Character.isLowerCase('A'));
System.out.println("isLowerCase():"+Character.isLowerCase('a'));
System.out.println("isLowerCase():"+Character.isLowerCase('0'));
System.out.println("---------------------------------");
System.out.println("isDigit():"+Character.isDigit('A'));
System.out.println("isDigit():"+Character.isDigit('a'));
System.out.println("isDigit():"+Character.isDigit('0'));
// char ch = 'a' ;
// System.out.println(Character.toUpperCase(ch));
}
}
6. 日期类(Data、Calender)
6.1Calender
Calender:日历类(java.util.Calender)。提供了一些诸如年月日中的日期等字段
静态功能:public static Calendar getInstance(),获取系统的当前时间。
成员方法: public int get(int field):根据给定日历字段----获取日历字段的值(系统的日历)
public abstract void add(int field,int amount):给指定的日历字段,添加或者减去时间偏移量 参数1:日历字段 参数2:偏移量
public class CalendarDemo {
public static void main(String[] args) {
//创建日历类对象
//获取系统的年月日
// Calendar c = new Calendar() ;
//public static Calendar getInstance()
Calendar calendar = Calendar.getInstance();
// System.out.println(calendar);
//获取年
//public static final int YEAR
int year = calendar.get(Calendar.YEAR) ;
//获取月:
//public static final int MONTH:0-11之间
int month = calendar.get(Calendar.MONTH) ;
//获取月中的日期
//public static final int DATE
//public static final int DAY OF MONTH : 每个月的第一天1
int date = calendar.get(Calendar.DATE) ;
System.out.println("当前日历为:"+year+"年"+(month+1)+"月"+date+"日");
System.out.println("------------------------------------------------");
//获取3年前的今天
//给year设置偏移量
// public abstract void add(int field,int amount)
// calendar.add(Calendar.YEAR,-3);
//获取
// year = calendar.get(Calendar.YEAR) ;
// System.out.println("当前日历为:"+year+"年"+(month+1)+"月"+date+"日");
//5年后的十天前
//需求:键盘录入一个年份,算出任意年份的2月份有多少天 (不考虑润月)
}
}
6.2 Date
java.util.date:表示特定瞬间,精确到毫秒。
此类允许格式化和解释字符串。
构造方法:public Date():当前系统时间格式
public Date(long date):参数为 时间毫秒值---->Date对象 (1970年1月1日…)
public class DateDemo {
public static void main(String[] args) {
//创建日期类对象
Date date = new Date() ;
System.out.println(date);
//Wed Jul 28 17:32:06 CST 2021 日期对象
System.out.println("------------------------");
long time = 60*60 ;
Date date2 = new Date(time) ;
System.out.println(date2);
}
}
java.util.Date获得的时间值转化为String,我们称为格式化过程。
DateForamt:抽象类----提供具体的日期/格式化的子类:SimpleDateFormat
format(Date对象)—>String
SimpleDateFormat:构造函数
public SimpleDateFormat():使用默认模式
public SimpleDateFormat(String pattern):使用指定的模式进行解析或者格式 (推荐)
参数,此部分必须一模一样
表示年 “yyyy”
表示月 “MM”
表示月中的日期 “dd”
一天中小时数 “HH”
分钟数 “mm”
秒数 “ss”
String(日期文本)转换为Date 我们称为解析过程
public Date parse(String source)throws ParseException
如果解析的字符串的格式和 public SimpleDateFormat(String pattern)的参数模式不匹配的话,就会出现解析异常!
public class DateDemo2 {
public static void main(String[] args) throws ParseException {
//Date----->String:格式化
//1)创建Date对象:表示当前系统时间对象
Date date = new Date() ;
System.out.println(date);
//2)创建SimpleDateForamt对象:(中间桥梁)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
//3)调用format:格式化
String strDate = sdf.format(date);
System.out.println(strDate);
System.out.println("--------------------------------");
//String---->Date(重点)
//1)有一个日期文本格式
//2)创建SimpleDateFormat对象指定一个模式
//3)调用解析parse方法
//注意:SimpleDateFormat解析模式必须和String日期文本格式匹配一致
String source = "2008-5-12" ; //日期文本
//SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日") ;
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd") ;
//public Date parse(String source)throws ParseException
Date dateResult = sdf2.parse(source);
System.out.println(dateResult);
}
}
7. Bigdecimal(针对浮点类型的精确计算))
Java提供的类: BigDecimal,在小数要进行精确计算的时候,还可以计算的同时保留小数点
后的有效位数
构造方法:
public BigDecimal(String value):数字字符串
成员方法:
public BigDecimal add(BigDecimal augend)加
public BigDecimal subtract(BigDecimal subtrahend)减
public BigDecimal multiply(BigDecimal multiplicand)乘
public BigDecimal divide(BigDecimal divisor):除(需得整除)
public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode)
参数1:除数 参数2:小数点后保留的有效位数 参数3:舍入模式 :四舍五入
public class BigDecimalDemo {
public static void main(String[] args) {
//System.out.println(1.01 / 0.36);
//创建BigDecimal对象
BigDecimal bg1 = new BigDecimal("1.01") ;
BigDecimal bg2 = new BigDecimal("0.36") ;
System.out.println("------------------------------------");
BigDecimal bg3 = new BigDecimal("10.0") ;
BigDecimal bg4 = new BigDecimal("5.05") ;
System.out.println(bg1.add(bg2));
System.out.println(bg1.subtract(bg2));
System.out.println(bg1.multiply(bg2));
// System.out.println(bg3.divide(bg4));//不保留(整除)
System.out.println(bg3.divide(bg4,3,BigDecimal.ROUND_HALF_UP));//四十五入
}
}
8.Math类
java.lang.Math :针对数学运算的工具类,提供了很多方法
-
public static int abs(int a):绝对值方法
-
public static double ceil(double a):向上取整
-
public static double floor(double a):向下取整
-
public static int max(int a,int b):获取最大值
-
public static int min(int a,int b):获取最小值
-
public static double pow(double a,double b):a的b次幂
-
public static double random():[0.0,1.0):随机数
-
public static long round(double a):四舍五入
-
public static double sqrt(double a):开平方根
一般工具类当中的构造方法都是私有的,直接对外提供静态方法,不让进行实例化!
public class MathDemo {
public static void main(String[] args) {
//abs()
System.out.println(Math.abs(-100));
// public static double ceil(double a):向上取整
System.out.println(Math.ceil(13.56));
// public static double floor(double a):向下取整
System.out.println(Math.floor(12.45));
// public static int max(int a,int b):获取最大值
System.out.println(Math.max(Math.max(10,30),50));//方法嵌套
//public static double pow(double a,double b):a的b次幂
System.out.println(Math.pow(2,3));
//ublic static long round(double a):四舍五入
System.out.println(Math.round(13.78));
// public static double sqrt(double a):开平方根
System.out.println(Math.sqrt(4));
}
}
9.Random类
java.util.Random类:伪随机数生成器
构造方法
public Random(): 产生一个随机生成器对象,通过成员方法随机数每次没不一样的(推荐)
public Random(long seed) :参数为long类型的值(随机数流:种子),每次通过成员方法获取随机数产生的随机数相同的
获取随机数的成员方法
public int nextInt():获取的值的范围是int类型的取值范围(-2的31次方到2的31次方-1)
public int nextInt(int n):获取的0-n之间的数据 (不包含n)
产生随机数的方法:
Math类的random方法 public static double random();
Random类:也能够去使用 无参构造方法 + 成员方法
public Random():+ public int nextInt(int n)
public class RandomDemo {
public static void main(String[] args) {
//创建一个随机数生成器
// public Random(long seed)
// Random random = new Random(1111) ;
//每次通过随机数生成器产生的随机不同
Random random = new Random() ;
//产生10个数
for(int x = 0 ; x < 10 ; x ++){
// public int nextInt():
// int num = random.nextInt();
//public int nextInt(int n)
int num = (random.nextInt(30)+1);
System.out.println(num);
}
}
}
10.关于数组对象
数组对象见明知意就是存储数组的对象
例:使用数组存储5个学生(姓名,年龄,性别),然后将数组进行遍历,获取出来每一个学生的信息!
Student类
public class Student {
private String name ;
private int age ;
private String gender ;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
Test类
public class Test {
public static void main(String[] args) {
//创建学生数组
// 数据类型[] 数组名称 = new 数据类型[长度] ; 学生对象数组
// 同样也可以静态
Student[] students = new Student[5] ;
//创建5个学生
Student s1 = new Student("文章",35,"男") ;
Student s2 = new Student("高圆圆",42,"女") ;
Student s3 = new Student("刘亦菲",33,"女") ;
Student s4 = new Student("马蓉",30,"女") ;
Student s5 = new Student("马保国",65,"男") ;
//给数组中的元素赋值
students[0] = s1 ;
students[1] = s2 ;
students[2] = s3 ;
students[3] = s4 ;
students[4] = s5 ;
//遍历学生数组
for(int x = 0 ; x < students.length ; x ++){
//System.out.println(students[x]);
System.out.println(students[x]);
}
}
}
11.集合
Collection:集合层次的根接口,一些集合允许元素重复(List),一些集合不允许元素重复(Set)
一些集合有序(存储和取出一致)(List),一些集合无序(存储和取出不一致)(Set)
JDK不提供此接口的任何直接实现:它提供了更具体的子接口的实现,如Set和List
Collection
List
最具体的子实现类ArrayList,LinkedList,Vector
Set
最具体的实现类TreeSet,HashSet
11.1 基本功能:
添加 boolean add(Object e):添加元素 E(Element)
删除 void clear() 暴力删除(将集合的素有元素全部干掉)
boolean remove(Object o):从集合中删除指定的元素
获取集合的元素数 :int size()
判断功能:boolean isEmpty():判断集合是否为空,为空元素,则返回true
boolean contains(Object o):判断集合中是否包含指定元素,包含则返回true
//@SuppressWarnings("all") //jdk提供的内置注解:压制警告 因为项目在部署的时候不允许出现警告。
public class CollectionDemo {
public static void main(String[] args) {
//创建Collection集合对象
//接口多态
Collection c = new ArrayList() ;
System.out.println(c);//ArrayList重写了Object的toString()方法
System.out.println("-----------------------------------------");
c.add("hello") ;
c.add(100) ;
c.add("javaee") ;
System.out.println(c);
System.out.println(c.size());
System.out.println("--------------------------");
System.out.println(c.contains("world"));
System.out.println(c.contains("javaee"));
System.out.println(c.isEmpty());
System.out.println(c);
}
}
11.2 Collection的高级功能
boolean addAll(Collection c):添加一个集合中的所有元素
boolean containsAll(Collection c):包含一个集合中的所有元素
boolean removeAll(Collection c):删除集合中的所有元素, (删除一个就算删除,返回True)
boolean retainAll(Collection c):A集合对B集合求交集, boolean的返回值是什么意思,交集的元素是保存在A中还是B中 将交集加入到A集合当中,若发生变换为True,否则为False
Student类同10 对象数组
public class CollectionDemo2 {
public static void main(String[] args) {
//创建两个Collection集合对象
Collection c1 = new ArrayList() ;
c1.add("abc1") ;
c1.add("abc2") ;
c1.add("abc3") ;
c1.add("abc4") ;
/* c1.add("abc5") ;
c1.add("abc6") ;
c1.add("abc7") ;*/
/* c1.add("abc5") ;
c1.add("abc6") ;
c1.add("abc7") ;*/
Collection c2 = new ArrayList() ;
c2.add("abc1") ;
c2.add("abc2") ;
c2.add("abc3") ;
c2.add("abc4") ;
c2.add("abc5") ;
c2.add("abc6") ;
c2.add("abc7") ;
System.out.println(c1);
System.out.println(c2);
System.out.println("---------------------------------");
//boolean addAll(Collection c):添加一个集合中的所有元素
// System.out.println(c1.addAll(c2));
//boolean containsAll(Collection c) :包含所有的元素算包含...
// System.out.println(c1.containsAll(c2));
//boolean removeAll(Collection c):删除集合中的所有元素, (删除一个算删除,还是删除所有):删除一个算删除(必须同时都被包含进去)
// System.out.println(c1.removeAll(c2));
// boolean retainAll(Collection c):A集合对B集合求交集, boolean的返回值是什么意思,交集的元素是保存在A中还是B中
/**
* A集合堆B集合求交集,交集的元素存储在A集合中,然后返回值的意思: 看A集合的元素是否有变化(之前的元素和现在交集的元素进行对比)
* 如果有变化,返回true;没有变化,则返回false
*
*/
System.out.println(c1.retainAll(c2)); //c1集合对c2集合取交集
System.out.println(c1);
System.out.println(c2);
System.out.println("-------------------------------------------");
//使用Colllection存储5个学生(姓名,年龄,性别),然后将Collection进行遍历,获取出来每一个学生的信息!
//创建一个Collection集合对象
Collection c = new ArrayList() ;
//创建5个学生 Student类同10 对象数组
Student s1 = new Student("宋江",45,"男") ;
Student s2 = new Student("李逵",35,"男") ;
Student s3 = new Student("武大郎",35,"男") ;
Student s4 = new Student("西门庆",30,"男") ;
Student s5 = new Student("吴用",40,"男") ;
//存储集合中
c.add(s1) ;
c.add(s2) ;
c.add(s3) ;
c.add(s4) ;
c.add(s5) ;
// Object[] toArray():将集合转换成了对象数组
Object[] objs = c.toArray();//数组存储的每一个数据类型 Object obj = new Student() ; //向上转型
//遍历数组
for(int x = 0 ; x < objs.length ; x ++){
Student student = (Student) objs[x]; //向下转型
System.out.println(student.getName()+"---"+student.getAge()+"---"+student.getGender());
}
}
}
11.3 迭代器
Collection的迭代器:集合的专有遍历方式
Iterator iterator():返回值类型接口类型,需要返回的子实现类对象
Iterator接口:
boolean hasNext():判断迭代器中是否存在下一个元素
Object next(): 获取下一个可以遍历的元素
给Collection中存储String类型,遍历出来
11.4List集合三个子实现类的特点
ArrayList
底层数据结构是数组,查询快,增删慢
通过arr[索引值]:查询到某个元素
线程角度: 线程不安全的类,实现不同步的 ----->执行效率高
特点:扩容机制:1.5倍的方式扩容
Integer[] arr = {11,22,33,44,55} ;
添加和删除元素:需要判断
在33这个元素后面新的元素,需要新建数组,长度是以前数组长度+1
判断加入的元素是否33元素
33以前,按照以前的元素在新的数组进行存储
33,继续存储
33以后的,加入88元素(给33以后的元素后面插入新的元素)
public ArrayList():无参构造方法:默认容量是10
//ArrayList扩容机制 底层代码实现,可以不看
public ArrayList(int initialCapacity)//:初始容量为空,指定初始容量大小
public ArrayList(int initialCapacity) {//10,20
if (initialCapacity > 0) {
10
this.elementData = new Object[initialCapacity];//创建数组对象elementData
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {//最小容量
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // protected transient int modCount = 0;:ArrayList父类中 默认0开始,统计变量
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity); //调用扩容方法
}
//扩容方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //右移动1位 //将左边的数据除以2的移动次幂 1/2
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
//计算最终容量大小
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
Vector
底层数据结构是数组,查询快,增删慢
线程角度:线程安全的类----同步的方法---->执行效率低
单线程程序中.考虑集合默认都会使用 ArrayList,多线程环境集合---->Vector集合
LinkedList
底层数据结构是链表,查询慢,增删快
线程角度:线程不安全的类---->不同步---->执行效率高
特有功能:
addFirst()
removeFirst()
getFirst()
xxxLast()
应用场景:模拟栈结构特点:先进后出
如果没有明确要求使用什么(List)集合的时候 ,默认都是用ArrayList
11.5List集合
List接口继承Collection,List集合特点: 有序(存储元素和取出元素一致) 允许元素重复
具备Collection相关的功能 Object [] toArray() Iterator iterator()
特有功能:
void add(int index,Object element):在指定的索引处插 入元素
Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
Object remove(int index):删除指定位置处的元素
Object set(int index,E element):修改指定位置处的元素(替换)
ListIterator listIterator():列表迭代器
ListIterator接口:void add(E e)有添加 remove():有删除
public class ListDemo {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<String >();
//添加元素
list.add("hello") ;
list.add("hello") ;
list.add("world") ;
list.add("world") ;
list.add("world") ;
list.add("javaEE") ;
list.add("javaEE") ;
// void add(int index,Object element):在指定的索引处插 入元素
list.add(1,"高圆圆");
//Object get(int index):获取指定位置处的元素 :返回的被获取到的元素内容
System.out.println(list.get(1));
// Object remove(int index):删除指定位置处的元素,返回被删除的元素
System.out.println(list.remove(2));
System.out.println("---------------------------------------");
//Object set(int index,E element):修改指定位置处的元素(替换)
System.out.println(list.set(1,"赵又廷"));
System.out.println(list);
}
}
11.5.1 java.util.ConcurrentModificationException:并发修改异常
集合在使用迭代器会经常出现的问题:并发修改异常, 当集合的元素正在被迭代器进行遍历,那么集合对象是不能够对元素进行增加或者删除 (一个线程正在遍历,一个线程在修改元素)
解决方案:
1)要么就是迭代器去遍历集合的元素,迭代器去添加元素 :列表迭代器才具备添加的动作
2)要么集合遍历,集合添加
public class ListTest2 {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<>() ;
//给添加元素
list.add("hello") ;
list.add("world") ;
list.add("javaee") ;
//使用迭代器遍历
//Iterator iterator()
/* Iterator<String> it = list.iterator(); //"hello","world","javaee"
while(it.hasNext()){
String s = it.next() ;//"hello","world","javaee"
//判断
if("world".equals(s)){
list.add("javaEE") ;//集合对象添加的元素,迭代器不知道
}
}
System.out.println(list);*/
//解决方案1: 1)要么就是迭代器去遍历集合的元素,迭代器去添加元素 :列表迭代器才具备添加的动作
//ListIterator
//void add(E e)
/*ListIterator<String> lit = list.listIterator();
while(lit.hasNext()){
//获取
String s = lit.next();
//判断是否存在"world"元素
if("world".equals(s)){
//列表迭代器添加
lit.add("javaEE");
}
}*/
//方案2:要么集合遍历,集合添加
//size()+get(int index)
for(int x = 0 ; x < list.size(); x ++){
String s = list.get(x);
if("world".equals(s)){//将常量放前面,防止出现NullPointerException
list.add("javaEE");
}
}
System.out.println(list);
}
}
11.5.2 List集合<非自定义对象>如何去重?
方式1:新建空集合思想,重新存储字符串类型并保证集合的元素唯一!
方式2:利用选择排序的思想去完成
选择排序的思想:使用0角标对应的元素依次和后面角标对应的元素进行比较,小的往前方法.依次这样比较,1角标,2角标…
List集合—集合列表角标从0开始,遍历当前集合,然后使用0角标对应的元素依次和后面对应的元素进行比较,如果后面的元素和前面的相同了,那么将后面的元素删除掉
public class ListTest3 {
public static void main(String[] args) {
//创建List集合
List<String> list = new ArrayList<>() ;
//现在给集合中添加重复的字符串数据
list.add("hello") ;
list.add("hello") ;
list.add("world") ;
list.add("world") ;
list.add("javaEE") ;
list.add("world") ;
list.add("javaEE") ;
list.add("android") ;
list.add("android") ;
list.add("ios") ;
//利用选择排序的思想完成
for(int x = 0 ; x < list.size()-1 ; x ++){
for(int y = x +1 ; y < list.size() ; y++){
//如果后面的元素和前面的元素相同
if(list.get(y).equals(list.get(x))){
//通过集合remove掉
list.remove(y) ; // public Object remove(int index)
//角标--
y -- ;
}
}
}
for(String s:list){
System.out.println(s);
}
}
}
11.5.3 List集合<自定义对象>如何去重?
Student s1 = new Student(“高圆圆”,42) ;
Student s2 = new Student(“高圆圆”,42) ;
成员信息如果一致,认为是同一个人,需要使用List集合去重!
方式1 :新建集合思想
contains(Object)方法依赖于Object的equals方法,所以集合存储的类型所在的类必须重写equals方法,否则默认使用Object的equals方法比较的地址值是否相同!
方式2 : 使用选择排序思想 将List存储的重复的学生对象进行重写!
public class ListTest4 {
public static void main(String[] args) {
//创建一个List集合
List<Student> list = new ArrayList<>() ;
//创建一些学生对象:有重复的成员信息
Student s1 = new Student("高圆圆",42) ;
Student s2 = new Student("高圆圆",42) ;
Student s3 = new Student("刘诗诗",39) ;
Student s4 = new Student("刘诗诗",39) ;
Student s5 = new Student("张佳宁",30) ;
Student s6 = new Student("文章",36) ;
Student s7 = new Student("文章",36) ;
Student s8 = new Student("姚笛",32) ;
//添加到集合中
list.add(s1) ;
list.add(s2) ;
list.add(s3) ;
list.add(s4) ;
list.add(s5) ;
list.add(s6) ;
list.add(s7) ;
list.add(s8) ;
//方式1:创建新的一个新集合
List<Student> newList = new ArrayList<>() ;
//遍历以前的集合获取每一个学生对象
for(Student s:list){
//如果当前newList不包含这个学生添加到新集合中
if(!newList.contains(s)){
newList.add(s) ;
}
}
//遍历新集合
for(Student student:newList){
System.out.println(student.getName()+"----"+student.getAge());
}
}
}
11.5.4 List集合的五种遍历方式
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class IteratorDemo {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student s1 = new Student("hh","nan");
Student s2 = new Student("hh2","nv");
Student s3 = new Student("hh3","nv");
list.add(s1);
list.add(s2);
list.add(s3);
//遍历方式1 //转成Object数组
Object[] obj = list.toArray();
for (int i = 0 ; i < obj.length ; i++){
Student s = (Student) obj[i];
System.out.println(s);
}
System.out.println("-------------------方法2--------");
//遍历方式2 迭代器
Iterator<Student> it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//遍历方式3 get() 和 size()结合
System.out.println("-------------------方法3--------");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//遍历方式4 list迭代器
System.out.println("--------------方法4------------");
ListIterator<Student> lit = list.listIterator();
while (lit.hasNext()){
System.out.println(lit.next());
}
//遍历方式5 增强for循环
System.out.println("--------------方法5------------");
if(list!=null){
for (Student s:list) {
System.out.println(s);
}
}else{
System.out.println("当前列表为空");
}
}
}
11.6 Vector集合
特有功能:
添加:public void addElement(Object obj):在vector对象的末尾添加元素 ------> 一直使用的add(Object e)
删除:public boolean removeElement(Object obj):删除元素
获取功能 :
public Object elementAt(int index):获取指定位置的元素---->类似于 public Object get(int index)
public Enumeration elements() :Vector集合的专有遍历方式---->类似于 Iterator literator()
boolean hasMoreElements():判断是否有更多的元素可以迭代
Object nextElement() 获取元素
public class VectorDemo {
public static void main(String[] args) {
//创建Vector集合对象
Vector<String> v = new Vector<>() ;
v.addElement("hello");
v.addElement("world");
v.addElement("SpringBoot");
v.addElement("SpringCloud") ;
//遍历:特有功能
Enumeration<String> en = v.elements(); //相当于Iterator
while(en.hasMoreElements()){
String s = en.nextElement();
System.out.println(s+"---"+s.length());
}
System.out.println("----------------------------------");
for(String s: v){
System.out.println(s+"----"+s.length());
}
}
}
11.7 插入排序
时间复杂度 O(n^2)
核心思想:使用1角标对应的元素进行和0角标比较
如果前面元素大,向右移动,确定角标1对应的元素的位置,再次使用2角标对应的元素依次和1和0都元素比较;依次这样比较。
public class InsertSortTest {
public static void main(String[] args) {
//定义一个Integer数组: Integer实现的自然排序:元素能够按照升序默认排序
Integer[] arr = {34,8,64,51,32,21} ;
System.out.println("排序前:");
printArr(arr);
//定义一个功能
insertSort(arr) ;
System.out.println("排序后:");
printArr(arr);
}
//插入排序
private static void insertSort(Integer[] arr) {
//定义一个变量j
int j ; //j记录当前角标的变化
//定义变量 : p:表示一个比较次数 p=1,2,3,4,5 (每一移动的元素的位置)
for(int p = 1 ; p < arr.length ; p ++ ){ //比较次数 p=2
//定义临时变量temp
Integer temp = arr[p] ; //temp = 8; temp = 64
//开始比较
for(j = p ; j>0 && temp.compareTo(arr[j-1])<0; j-- ){ // compareTo()见下面解释
//数据移动
arr[j] = arr[j-1] ;
}
//确定temp的位置:8的位置 64的位置:p=2
arr[j] = temp ; // 没有移动
}
}
public static void printArr(Integer[] arr){
System.out.print("[");
for(int x = 0 ; x < arr.length ; x ++){
if(x == arr.length -1){
System.out.println(arr[x] +"]");
}else{
System.out.print(arr[x]+", ");
}
}
}
}
public int compareTo(Integer anotherInteger) { // 8 34
return compare(this.value, anotherInteger.value);
8,34
}
8 34
public static int compare(int x, int y) { //提高程序的执行效率
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}