admin管理员组文章数量:1546100
Java基础2
学习黑马java系列课程所作笔记
文章目录
- Java基础2
- 四、面向对象高级
- 1.面向对象高级一
- 1.1static
- 1.1.1static修饰成员变量
- 1.1.2static修饰成员变量的应用场景
- 1.1.3static修饰成员方法
- 1.1.4static修饰成员方法的应用场景
- 1.1.5staticd的注意事项
- 1.1.6staticd的应用知识:代码块
- 1.1.7staticd的应用知识:单例设计模式
- 1.2面向对象三大特征之二:继承
- 1.2.1认识继承、特点
- 1.2.2继承的好排除、应用场景
- 1.2.3继承的相关注意事项
- 1.2.3.1权限修饰符
- 1.2.3.2单继承与Object类
- 1.2.3.3方法重写
- 1.2.3.4子类中访问其他成员的特点
- 1.2.3.5子类构造器的特点
- 1.2.3.6子类构造器应用场景
- 2.面向对象高级二
- 2.1面向对象的三大特征之三:多态
- 2.1.1认识多态
- 2.1.2使用多态的好处
- 2.1.3多态下的类型转换问题
- 2.2final
- 2.2.1认识final
- 2.2.2补充知识:常量详解
- 2.3抽象类
- 2.3.1认识抽象类
- 2.3.2使用抽象类的好处
- 2.3.3抽象类的常见应用场景:模板方法设计模式
- 2.4接口
- 2.4.1接口概述
- 2.4.2接口的好处(重点)
- 2.4.3接口的综合案例(重点)
- 2.4.4接口的其他细节:JDK8开始,接口中新增的三种方法
- 2.4.5接口的其他细节:接口的多继承、使用接口的注意事项【了解】
- 3.面向对象高级三
- 3.1内部类
- 3.1.1成员内部类(了解)
- 3.1.2静态内部类(了解)
- 3.1.3局部内部类(了解)
- 3.1.4匿名内部类(重点)
- 3.1.4.1认识匿名内部类
- 3.1.4.2匿名内部类使用场景
- 3.2枚举
- 3.2.1认识枚举
- 3.2.1枚举的常见应用场景
- 3.3泛型
- 3.3.1认识泛型
- 3.3.2泛型类
- 3.3.3泛型接口
- 3.3.4泛型方法、通配符、上下限
- 3.3.5 泛型的注意事项:擦除问题、基本数据类型问题
- 3.4常用API(一)
- 3.4.1API概述
- 3.4.2Object
- 3.4.3Objects
- 3.4.4包装类
- 3.4.5 StringBuild与StringBuffer
- 3.4.6 StringJoiner
- 3.5常用API(二)
- 3.5.1 Math、System、Runtime
- 3.5.2BigDecimal
- 3.5.3JDK8之前传统的日期、时间
- 3.5.3.1Date
- 3.5.3.2SimpleDateFormat
- 3.5.3.3练习:秒杀活动
- 3.5.3.4Calendar
- 3.5.4JDK8之前传统的日期、时间
- 3.5.4.1为什么要学JDK8新增的时间?
- 3.5.4.2LocalDate、LocalTime、LocalDateTime
- 3.5.4.3 Instant
- 3.5.4.4DateTimeFormatter
- 3.5.4.5Period与Duration
- 3.5.5Arrays
- 3.5.6JDK8新特性:Lambda表达式
- 3.5.6.1认识Lambda表达式
- 3.5.6.2Lambda表达式的省略规则
- 3.5.7JDK8新特性:方法引用
四、面向对象高级
1.面向对象高级一
1.1static
1.1.1static修饰成员变量
- 叫静态,可以修饰成员变量、成员方法
成员变量按照有无static修饰,分为两种:
- 类变量:有static修饰,属于类,在计算机中只有一份发,会被类的全部变量共享
- 实例变量(变量的对象):无static修饰,属于每个对象自己。
Student
package com.itheima.d1_staticDemo;
public class Student {
//类变量
static String name;
//实例变量(对象的变量)
int age;
}
Test
package com.itheima.d1_staticDemo;
public class Test {
public static void main(String[] args) {
//目标:掌握有无Static修饰成员变量的用法,特点。
//1.类变量的用法
//类名.类变量(推荐)
Student.name="袁华";
//对象.类变量(不推荐)
Student s1=new Student();
s1.name="马冬梅";
Student s2=new Student();
s2.name="秋雅";
System.out.println(s1.name);
System.out.println(Student.name);
//2.实例变量的用法
s1.age=23;
s2.age=18;
System.out.println(s1.age);
//System.out.println(Student.age);报错
}
}
成员变量的执行原理
1.1.2static修饰成员变量的应用场景
类变量的应用场景
- 在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住。
案例导学
- 系统启动后,要求用户类可以记住自己创建了多少个用户对 象了。
Test2
package com.itheima.d1_staticDemo;
public class Test2 {
public static void main(String[] args) {
//目标:通过案例理解类变量的应用场景
User u1=new User();
User u2=new User();
User u3=new User();
User u4=new User();
System.out.println(User.number);
}
}
User
package com.itheima.d1_staticDemo;
public class User {
//类变量一般用public修饰,对外暴露,方便被外界访问
public static int number;
public User(){
//User.number++;
//在同一个类中,访问自己类的类变量,才可以省略类名不写
number++;
}
}
1.1.3static修饰成员方法
-
类方法:有static修饰的成员方法,属于类。
-
实例方法:无static修饰的成员方法,属于对象。
Student
package com.itheima.d2_static_method;
public class Student {
double score;
//类方法
public static void printHelloWorld(){
System.out.println("Hello World");
}
public void printPass() {
System.out.println("成绩:" +
(score >= 60 ? "及格" : "不及格"));
}
}
Test
package com.itheima.d2_static_method;
public class Test {
public static void main(String[] args) {
//目标:掌握有无static修饰方法的用法。
//1、类方法的用法
//类名。类方法(推荐)
Student.printHelloWorld();
//对象.类方法(不推荐)
Student s = new Student();
s.printHelloWorld();
//2实例方法的用法
//对象.实例方法
s.printPass();
//Student.printPass();报错
}
}
成员方法执行原理
补充知识:搞懂main方法
- 虚拟机会用Test类来执行main()方法
- 括号里表示可以传一些参数进去,实际开发中没啥用
1.1.4static修饰成员方法的应用场景
类方法的常见应用场景
- 类方法最常见的应用场景是做工具类。
工具类是什么?
- 工具类中的方法都是一些类方法,每个方法都是用来完成一个功能的,工具类是给开发人员共同使用的。
使用类方法来设计工具类有啥好处?
- 提高了代码复用:调用方便,提高了开发效率。
案例
LoginDemo
package com.itheima.d3_util;
/**
登录界面
*/
public class LoginDemo {
public static void main(String[] args) {
//定义两个变量,一个记住最终产生的随机验证码,一个是记住可能
System.out.println(MyUtil.createCode(4));
}
}
RegisterDemo
package com.itheima.d3_util;
public class RegisterDemo {
public static void main(String[] args) {
System.out.println(MyUtil.createCode(6));
}
}
MyUtil
package com.itheima.d3_util;
import java.util.Random;
public class MyUtil {
private MyUtil(){
}
public static String createCode(int n){
String code ="";
String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random r=new Random();
//2、开始定义一个循环产生每位随机字符
for (int i=0;i < n;i++){
//3、随机一个字符范围内的索引。
int index = r.nextInt(data.length());
//4、根据索引去全部字符中提取该字符
code+=data.charAt(index);//code=code+字符
}
return code;
}
}
为什么工具类中的方法要用类方法,而不用实例方法?
- 实例方法需要创建对象来调用,此时对象只是为了调用方法,对象占内存,这样会浪费内存。
- 类方法,直接用类名调用即可,调用方便,也能节省内存。
多学一招:
工具类没有创建对象的需求,建议将工具类的构造器进行私有。
1.1.5staticd的注意事项
- 类方法中可以直接访问类的成员,不可以直接访问实例成员。
- 实例方法中既可以直接访问类成员,也可以直接访问实例成员。
- 实例方法中可以出现ths关键字,类方法中不可以出现ths关键字的。
示例:
Student
package com.itheima.d4_static_attention;
public class Student {
static String schoolName;//类变量
double score;//实例变量
//1、类方法中可以直接访问类的成员,不可以直接访问实例成员。
public static void printHelloWorld() {
//注意:同一个类中,访问类成员,可以省略类名不写
//Student.schoolName="黑马";
//Student.printHelloWorld2();
schoolName="黑马";
printHelloWorld2();
//System.out.println(score);报错
//printPass();报错
//System.out.println(this);报错
}
//2、实例方法中既可以直接访问类成员,也可以直接访问实例成员。
//实例方法
//3、实例方法中可以出现this关键字,类方法中不可以出现this关键字的
public static void printHelloWorld2(){
}
public void printPass(){
schoolName="黑马";
printHelloWorld2();
System.out.println(score);
printPass2();//相当于this.printPass2();
System.out.println(this);//会输出地址
}
public void printPass2(){
}
}
Test
package com.itheima.d4_static_attention;
public class Test {
public static void main(String[] args) {
Student s1=new Student();
s1.printPass();
}
}
1.1.6staticd的应用知识:代码块
代码块概述
-
代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类)。
代码块分为两种: -
静态代码块:
->格式:static{}
->特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。
->作用:完成类的初始化,例如:对类变量的初始化赋值。 -
实例代码块:
->格式:{}
->特点:每次创建对象时,执行实例代码块,并在构造器前执行。
->作用:和构造器一样,都是用来完成对象的初始化的心例如:对实例变量进行初始化赋值。
示例
Student
package com.itheima.d5_block;
public class Student {
static int number=80;
static String schoolName;
//静态代码块
static{
System.out.println("静态代码块执行了~~");
schoolName="黑马";
}
//实例代码块
{
System.out.println("实例代码块执行了~~");
System.out.println("有人创建了对象:"+this);
//可以把构造器中重复代码拿到实例代码块中
}
public Student(){
System.out.println("无参数构造器执行了~~");
}
public Student(String name){
System.out.println("有参数构造器执行了~~");
}
}
Test
package com.itheima.d5_block;
public class Test {
public static void main(String[] args) {
//目标:认识两种代码块,了解他们的特点和基本作用
System.out.println(Student.number);
System.out.println(Student.number);
System.out.println(Student.number);
System.out.println(Student.schoolName);//黑马
System.out.println("-----------------------------------------");
Student s1=new Student();
System.out.println("-----------------------------------------");
Student s2 = new Student("张三");
}
}
1.1.7staticd的应用知识:单例设计模式
什么是设计模式(Design pattern)?
- 一个问题通常有种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。
- 设计模式有20多种,对应20多种软件开发中会遇到的问题。
关于设计模式的学习,主要学什么?
- 解决什么问题?
- 怎么写?
单例设计模式
- 确保一个类只有一个对象。
写法(饿汉式)
- 把类的构造器私有。
- 定义一个类变量记住类的一个对象。
- 定义一个类方法,返回对象。
示例
A
package com.itheima.d6_singleInstance;
public class A {
//2.定义一个类变量记住类顶点的一个对象
private static A a=new A();
//1.必须私有类的构造器
private A(){
}
//定义一个类方法返回类的对象
public static A getObject() {
return a;
}
}
Test1
package com.itheima.d6_singleInstance;
public class Test1 {
public static void main(String[] args) {
//目标:掌握单例设计模式的写法
System.out.println(A.getObject());
A a1=A.getObject();
A a2=A.getObject();
System.out.println(a1);
System.out.println(a2);
}
}
懒汉式单例设计模式
- 拿对象时,才开始创建对象。
写法
- 把类的构造器私有。
- 定义一个类变量用于存储对象。
- 提供一个类方法,保证返回的是同一个对象。
B
package com.itheima.d6_singleInstance;
public class B {
//2.定义一个类变量,用于存储这个类的一个对象。
private static B b;
//1.把类的构造器私有
private B(){
}
//定义一个类方法,保证第一次调用时才创建一个对象,后面调用时都会用同一个对象返回
public static B getInstance(){
if(b==null){
b=new B();
}
return b;
}
}
Test2
package com.itheima.d6_singleInstance;
//目标:掌握懒汉式单例的写法
public class Test2 {
public static void main(String[] args) {
B b1=B.getInstance();//第一次拿对象
B b2=B.getInstance();
System.out.println(b1 == b2);
}
}
1.2面向对象三大特征之二:继承
1.2.1认识继承、特点
什么是继承?
- Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系。
继承的特点 - 子类能继承父类的非私有成员(成员变量、成员方法)。
继承后对象的创建 - 子类的对象是由子类、父类共同完成的。
示例:
A
package com.itheima.d7_extends;
//父类
public class A {
//公开成员
public int i;
public void print1(){
System.out.println("===print1===");
}
//私有成员
private int j;
private void print2(){
System.out.println("===print2===");
}
}
B
package com.itheima.d7_extends;
//子类
public class B extends A{
private int k;
//子类可以继承父类的非私有成员
public void print3(){
System.out.println(i);
print1();
//System.out.println(j);
//print2();private,不能继承,报错
}
}
Test
package com.itheima.d7_extends;
public class Test {
public static void main(String[] args) {
//认识继承,掌握继承的特点
B b=new B();
System.out.println(b.i);
//System.out.println(b.j);//
//System.out.println(b.k);
b.print1();
//b.print2();
b.print3();
}
}
继承的执行原理
1.2.2继承的好排除、应用场景
使用继承有什么好处?
- 减少重复代码的编写。
示例:
People
package com.itheima.d8_extends_application;
public class People {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Teacher
package com.itheima.d8_extends_application;
public class Teacher extends People{
private String skill;
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
public void printInfo(){
System.out.println(getName()+"具备的技能:"+skill);
}
}
Test
package com.itheima.d8_extends_application;
public class Test {
public static void main(String[] args) {
//目标:弄清楚继承的好处
Teacher t=new Teacher();
t.setName("波仔");
t.setSkill("Java");
System.out.println(t.getName());
System.out.println(t.getSkill());
t.printInfo();
}
}
1.2.3继承的相关注意事项
1.2.3.1权限修饰符
什么是权限修饰符?
- 就是是用来限制类中的成员(成员变量、成员方法、构造器、代码块)能够被访问的范围。
权限修饰符有几种?各自的作用是什么?
示例:
Demo
package com.itheima.d9_modifer;
public class Demo {
public static void main(String[] args) {
//目标:掌握不同修饰类的作用
Fu f=new Fu();
//f.privateMethod();报错
f.method();
f.protectedMethod();
f.publicMethod();
}
}
Fu
package com.itheima.d9_modifer;
public class Fu {
//1、私有:只能在本类中访问
private void privateMethod(){
System.out.println("==private==");
}
//2、缺省:本类,同一个包下的类
void method(){
System.out.println("==缺省=");
}
//3、protected:本类,同一个包下的类,任意包下的子类
protected void protectedMethod(){
System.out.println("==protected==");
}
//4、pUbL1c:本类,同一个包下的类,任意包下的子类,任意包下的任意类
public void publicMethod(){
System.out.println("==public==");
}
public void test(){
privateMethod();
method();
protectedMethod();
publicMethod();
}
}
Demo2
package com.itheima.d10_modifer;
import com.itheima.d9_modifer.Fu;
public class Demo2 {
public static void main(String[] args) {
Fu f=new Fu();
//f.protectedMethod();报错
//f.method();报错
//f.protectedMethod();报错
f.publicMethod();
//注意,protected可以在子类里访问,不能在子类的对象里访问
// f.protectedMethod();
}
}
Zi
package com.itheima.d10_modifer;
import com.itheima.d9_modifer.Fu;
public class Zi extends Fu {
public void test() {
//privateMethod();报错
//method;报错
protectedMethod();
publicMethod();
}
}
1.2.3.2单继承与Object类
Java是单继承的,Java中的类不支持多继承,但是支持多层继承。
Java为何不支持多继承?
Object类
- object类是java所有类的祖宗类。我们写的任何一个类 ,其实都object的子类或子孙类
示例:
package com.itheima.d11_extends_feature;
public class Test {
public static void main(String[] args) {
//目标:掌握继承的两个注意事项事项。
//1、Java是单继承的:一个类只能继承一个直接父类:Java中的类不支持多继承,但是支持多层继承。
//2、Object类是Java中所有类的祖宗。
A a=new A();
B b=new B();
b.hashCode();
}
}
class A{}//extends Object{}
class B extends A{}
//class C extends A,B{}报错
class C extends B{}//支持多层继承
1.2.3.3方法重写
什么是方法重写
- 当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
- 注意:重写后,方法的访问,Java会遵循就近原则。
示例:
A
package com.itheima.d12_extends_override;
public class A {
public void print1(){
System.out.println("111");
}
public void print2(int a,int b){
System.out.println("111111");
}
}
B
package com.itheima.d12_extends_override;
public class B extends A{
//方法重写
public void print1(){
System.out.println(666);
}
public void print2(int a,int b){
System.out.println("66666");
}
}
C
package com.itheima.d12_extends_override;
public class C extends B{
}
Test
package com.itheima.d12_extends_override;
public class Test {
public static void main(String[] args) {
//目标:认识方法重写,掌握方法重写的常见应用场景。
B b=new B();
b.print1();
b.print2(2,3);
C c=new C();
c.print1();
}
}
方法重写的其它注意事项
- 重写小技巧:使用Override:注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好
- 子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)。
- 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
- 私有方法、静态方法不能被重写,如果重写会报错的。
方法重写在开发中的常见应用场景
- 子类重写Object类的toString(方法,以便返回对象的内容。
示例:
Student
package com.itheima.d12_extends_override;
public class Student {
private String name;
private int age;
public String toString(){
return "Student{name="+name+",age="+age+"}";
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
}
Test
package com.itheima.d12_extends_override;
public class Test {
public static void main(String[] args) {
//目标:认识方法重写,掌握方法重写的常见应用场景。
B b=new B();
b.print1();
b.print2(2,3);
C c=new C();
c.print1();
System.out.println("----------------------------------------------------");
Student s =new Student("波妞",19);
System.out.println(s);//实际上是s.toString();
}
}
直接右键生成点toString()即可
1.2.3.4子类中访问其他成员的特点
- 在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则的。
- 先子类局部范围找。
- 然后子类成员范围找。
- 然后父类成员范围找,如果父类范围还没有找到则报错。
- 如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?
- 可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法
示例:
F
package com.itheima.d13_extends_visit;
public class F {
String name="父类名字";
public void print1(){
System.out.println("父类的print1方法执行" +
"" +
"");
}
}
Z
package com.itheima.d13_extends_visit;
public class Z extends F{
String name="子类名称";
public void showName(){
String name="局部名称";
System.out.println(name);//局部名称
System.out.println(this.name);//子类成员
System.out.println(super.name);
}
@Override
public void print1(){
System.out.println("==子类的print1方法执行了==");
}
public void showMethod(){
print1();//父类的
super.print1();
}
}
Test
package com.itheima.d13_extends_visit;
public class Test {
public static void main(String[]args){
//目标:掌握子类中访问其他成员的特点:就近原则。
Z z=new Z();
z.showName();
z.showMethod();
}
}
1.2.3.5子类构造器的特点
子类构造器的特点:
- 子类的全部构造器,都会先调用父类的构造器,再执行自己。
子类构造器是如何实现调用父类构造器的:
- 默认情况下,子类全部构造器的第一行代码都是Supr0(写不写都有),它会调用父类的无参数构造器。
- 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(),指定去调用父类的有参数构造器。
示例:
Test
package com.itheima.d14_extends_constructor;
class F{
// public F(){
// System.out.println("==父类F的无参数构造器执行了==");
//}
public F(String name){
System.out.println("==父类F的有参数构造器执行了==");
}
}
class Z extends F{
public Z(){
//super();//默认存在的
super("波妞");
System.out.println("==子类Z的无参数构造器执行了==");
}
public Z(String name){
super("波妞");
System.out.println("==子类Z的有参数构造器执行了==");
}
}
public class Test {
public static void main(String[] args) {
//目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景
Z z=new Z();
Z z2=new Z("波妞");
}
}
如果父类和子类都有各自的无参和有参构造器,子类无论调用自己的有参还是无参构造器,都会调用父类的无参构造器
1.2.3.6子类构造器应用场景
示例:
package com.itheima.d14_extends_constructor;
public class Test2 {
public static void main(String[] args) {
//目标:搞清楚子类构造器为什么要调用父类构造器,有啥应用场景。
Teacher t=new Teacher("李四",36,"java");
System.out.println(t.getName());
System.out.println(t.getAge());
System.out.println(t.getSkill());
}
}
class Teacher extends People{
private String skill;
public Teacher(String name, int age, String skill) {
super(name, age);
this.skill = skill;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
class People{
private String name;
private int age;
public People() {
}
public People(String name, int age) {
this.name = name;
this.age = 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;
}
}
- 子类构造器调用父类构造器的常见应用场景
- 子类构造器可以通过调用父类构造器,把对象中包含父类这部分的数据先初始化赋值,再回来把对象里包含子类这部分的数据也进行初始化层值。
补充知识:ths(…)调用兄弟构造器
- 任意类的构造器中,是可以通过this(.…)去调用该类的其他构造器的。
示例:
Test3
package com.itheima.d14_extends_constructor;
public class Test3 {
public static void main(String[] args) {
//目标:掌握在类的构造器中,通过this(...)调用兄弟构造器的作用。
Student s1=new Student("李四",26,"家里蹲大学");
//需求:如果学生没有填写学校,那么学校默认就是黑马程序员
Student s2=new Student("张三",28);
System.out.println(s2.getName());
System.out.println(s2.getAge());
System.out.println(s2.getSchoolName());
}
}
class Student{
private String name;
private int age;
private String schoolName;
public Student() {
}
public Student(String name, int age) {
//this.name = name;
//this.age = age;
//this.schoolName = "黑马程序员";
this(name,age,"黑马程序员");
}
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age;
this.schoolName = schoolName;
}
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 getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
}
注意:不能在一个构造器里同时写this和super构造器,因为this借用兄弟构造器时已经调用了一次父类构造器,不能调用两次super构造器,并且,this和super构造器都得放在构造器的第一行
2.面向对象高级二
2.1面向对象的三大特征之三:多态
2.1.1认识多态
- 多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
多态的具体代码体现
多态的前提
- 有继承/实现关系;存在父类引用子类对象;存在方法重写。
多态的一个注意事项
- 多态是对象、行为的多态,Jva中的属性(成员变量)不谈多态。
示例:
People
package com.itheima.d1_polymorphism;
//父类
public class People {
public String name="父类People的名称";
public void run(){
System.out.println("人可以跑");
}
}
Student
package com.itheima.d1_polymorphism;
public class Student extends People{
public String name="子类Student的名称";
@Override
public void run(){
System.out.println("学生跑的很快!");
}
}
Teacher
package com.itheima.d1_polymorphism;
public class Teacher extends People{
public String name="子类Teacher的名称";
public void run(){
System.out.println("老师跑不动");
}
}
Test
package com.itheima.d1_polymorphism;
public class Test {
public static void main(String[] args) {
//目标:认识多态:对象多态、行为多态。
//1.对象多态
People p1=new Teacher();
p1.run();//识别技巧:编译看左边,运行看右边
System.out.println(p1.name);
People p2=new Student();
p2.run();
System.out.println(p2.name);
}
}
2.1.2使用多态的好处
- 在多态形式下,右边对象解耦合的,更便于扩展和维护。
- 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
多态下会产生的一个问题,怎么解决?
- 多态下不能使用子类的独有功能。
示例:
People
package com.itheima.d2_polymorphism.d1_polymorphism;
//父类
public class People {
public String name="父类People的名称";
public void run(){
System.out.println("人可以跑");
}
}
Student
package com.itheima.d2_polymorphism.d1_polymorphism;
public class Student extends People {
public String name="子类Student的名称";
@Override
public void run(){
System.out.println("学生跑的很快!");
}
public void test(){
System.out.println("学生需要考试");
}
}
Teacher
package com.itheima.d2_polymorphism.d1_polymorphism;
public class Teacher extends People {
public String name="子类Teacher的名称";
public void run(){
System.out.println("老师跑不动");
}
public void teach(){
System.out.println("老师需要教知识");
}
}
Test
package com.itheima.d2_polymorphism.d1_polymorphism;
public class Test {
public static void main(String[] args) {
//目标:理解多态的好处
//好处1:可以实现解耦合,右边对象可以随时切换,后续业务随即改变
People p1=new Student();
p1.run();
//p1.test;多态下存在的问题:无法直接调用子类的独有功能
Student s=new Student();
go(s);
Teacher t=new Teacher();
go(t);
}
//好处2:可以使用父类类型的变量作为形参,可以实现一切子类对象
public static void go(People p){
}
}
2.1.3多态下的类型转换问题
-
自动类型转换:父类 变量名=new 子类();
-
强制类型转换:子类 变量名=(子类)父类变量
强制类型转换的一个注意事项
- 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错。
- 运行时,如果发现对象的真实类型与强转后的类型不同,就会报==类型转换异常(ClassCastException)==的错误出来。
强转前,Java建议: - 使用instanceof关键字,判断当前对象的真实类型,再进行强转。
是Student的子类也行
示例:
Test
package com.itheima.d2_polymorphism.d1_polymorphism;
public class Test {
public static void main(String[] args) {
//目标:理解多态的好处
//好处1:可以实现解耦合,右边对象可以随时切换,后续业务随即改变
People p1=new Student();
p1.run();
//p1.test;多态下存在的问题:无法直接调用子类的独有功能
//强制类型转换
Student s1=(Student) p1;
s1.test();
//强制类型转换存在的问题:编译阶段有继承或者实现关系就可以强制类型转换,
// 但是运行时就可能出现类型转换异常
//Teacher t1=(Teacher) p1;//运行时出现异常:ClassCastException
System.out.println("---------------------------------");
//好处2:可以使用父类类型的变量作为形参,可以实现一切子类对象
People s=new Student();
go(s);
People t=new Teacher();
go(t);
}
//好处2:可以使用父类类型的变量作为形参,可以实现一切子类对象
public static void go(People p){
System.out.println(p.name);
p.run();
if (p instanceof Student){
Student s=(Student) p;
s.test();
}
else{
Teacher t=(Teacher) p;
t.teach();
}
}
}
2.2final
2.2.1认识final
- final关键字是最终的意思,可以修饰(类、方法、变量)
- 修饰类:该类被称为最终类,特点是不能被继承了。
- 修饰方法。该方法被称为最终方法,特点是不能被重写了。
- 修饰变量:该变量只能被赋值一次。
final修饰变量的注意
- final修饰基本类型的变量,变量存储的数据不能被改变。
- fial修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。
示例:
package com.itheima.da_final;
public class Test {
//常量: static final修饰的成员变量,建议名称全部大写,多个单词下划线连接
//private final String name="猪八戒";这种用法无意义,final一般不用来修饰实例变量
// public static final String schoolname;报错,必须赋一次值
public static final String schoolname="黑马大学";
//schoolname="白马大学";二次赋值,报错
public static void main(String[] args) {
//目标:认识final的作用
//3.final可以修饰变量总规则:有且仅能赋值一次
//变量:一.局部变量 二.成员变量:1.静态成员变量2.实例成员变量
final int a;
a=1;
//a=2;不能二次赋值,会出错
final int[] arr={11,22,33};
arr[2]=333;
}
public static void buy(final double z){
//z=0.1;只能接一次值,内部不能变
}
}
//1.final修饰类,类不能被继承
final class A{
}
//class B extends A{}
//2.final修饰方法,方法不能被重写
class C{
public final void test(){
}
}
class D extends C{
//@Override
// public final void test(){}
}
2.2.2补充知识:常量详解
常量
- 使用了static final修饰的成员变量就被称为常量;
- 作用:通常用于记录系统的配置信息。
注意!常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来。
使用常量记录系统配置信息的优势、执行原理
- 代码可读性更好,可维护性也更好。
- 程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量, 这样可以保证使用常量和直接用字面量的性能是一样的。
示例
Test2
package com.itheima.da_final;
public class Test2 {
public static final String SCHOOL_NAME="黑马大学";
public static void main(String[] args) {
System.out.println(SCHOOL_NAME);
System.out.println(SCHOOL_NAME);
System.out.println(SCHOOL_NAME);
System.out.println(SCHOOL_NAME);
}
}
2.3抽象类
2.3.1认识抽象类
什么是抽象类?
- 在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。
- abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
抽象类的注意事项、特点 - 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
- 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
- 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
示例
A
package com.itheima.d4_abstract;
//抽象类
public abstract class A {
private String name;
public static String schoolName;
public A(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//抽象方法:必须用abstract修饰,只有方法签名,一定不能有方法体
public abstract void run();
}
B
package com.itheima.d4_abstract;
public class B extends A{
//一个类继承了抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
@Override
public void run(){}
}
Test
package com.itheima.d4_abstract;
public class Test {
public static void main(String[] args) {
//目标:认识抽象类和其特点。
//注意:抽象类不能创建对象
//A a=new A();错误
//a.run();
}
}
2.3.2使用抽象类的好处
-父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们设计这样的抽象类,就是为了更好的支持多态。
示例
Animal
package com.itheima.d5_abstract2;
public abstract class Animal {
private String name;
public abstract void cry();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Cat
package com.itheima.d5_abstract2;
public class Cat extends Animal{
@Override
public void cry(){
System.out.println(getName()+"喵喵喵地叫");
}
}
Dog
package com.itheima.d5_abstract2;
public class Dog extends Animal{
@Override
public void cry(){
System.out.println(getName()+"汪汪汪地叫");
}
}
Test
package com.itheima.d5_abstract2;
public class Test {
public static void main(String[] args) {
//目标:认识抽象类的好处
Animal a=new Cat();
a.setName("叮当猫");
a.cry();
}
}
2.3.3抽象类的常见应用场景:模板方法设计模式
模板方法设计模式解决了什么问题?
- 解决方法中存在重复代码的问题。
模板方法设计模式的写法 - 1、定义一个抽象类。
- 2、在里面定义2个方法
一个是模板方法:把相同代码放里面去。
一个是抽象方法:具体实现交给子类完成。
示例
多学一招:使用final关键字修饰模板方法
- 模板方法是给对象直接使用的,不能被子类重写。
- 一旦子类重写了模板方法,模板方法就失效了。
People
package com.itheima.d6_abstract_template;
public abstract class People {
//设计模板方法
//1.定义模板方法
public final void write(){
System.out.println("\t\t\t\t\t《我的爸爸》");
//2.模板方法不知道正文到底怎么写,但知道子类肯定要写
System.out.println(writeMain());
System.out.println("我的爸爸太好了");
}
//3.定义一个抽象方法写正文,具体的实现交给子类来完成
public abstract String writeMain();
}
Student
package com.itheima.d6_abstract_template;
public class Student extends People{
@Override
public String writeMain(){
return "我的爸爸很爱我";
}
}
Teacher
package com.itheima.d6_abstract_template;
public class Teacher extends People{
@Override
public String writeMain(){
return "我的爸爸很辛苦";
}
}
Test
package com.itheima.d6_abstract_template;
public class Test {
public static void main(String[] args) {
//目标:搞清楚抽象类的应用场景之一:经常用来设计模板方法设计模式,
//场景:写作文,老师和学生各自写一篇,开头结尾一样,正文自由发挥;
Teacher t=new Teacher();
t.write();
}
}
2.4接口
2.4.1接口概述
认识接口
- Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构:接口。
- 注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。
- 一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义为抽象类
示例:
A
package com.itheima.d7_interface;
public interface A {
//成员变量(常量)
String SCHOOL_NAME="黑马程序员";//加不加public static final无所谓
//成员方法(抽象方法),加不加public abstract无所谓
void test();//不能有方法体{}
}
B
package com.itheima.d7_interface;
public interface B {
void testb1();
void testb2();
}
C
package com.itheima.d7_interface;
public interface C {
void testc1();
void testc2();
}
D
package com.itheima.d7_interface;
//
public class D implements B,C{
@Override
public void testb1() {
}
@Override
public void testb2() {
}
@Override
public void testc1() {
}
@Override
public void testc2() {
}
}
Test
package com.itheima.d7_interface;
public class Test {
public static void main(String[] args) {
//目标:认识接口
System.out.println(A.SCHOOL_NAME);
// A a=new A();接口无法创建对象
D d=new D();
}
}
2.4.2接口的好处(重点)
- 弥补了类单继承的不足,一个类同时可以实现多个接口。
- 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。
示例
Test
package com.itheima.d8_interface2;
import com.itheima.d5_abstract2.Animal;
import com.itheima.d5_abstract2.Dog;
public class Test {
public static void main(String[] args) {
//目标:弄清楚使用接口的好处。
Driver s=new A();
s.drive();
Driver d=new B();
d.drive();
}
}
class B implements Driver{
@Override
public void drive(){
}
}
class A extends Student implements Driver, Singer{
@Override
public void drive() {
}
@Override
public void sing() {
}
}
class Student{
}
interface Driver{
void drive();
}
interface Singer {
void sing();
}
2.4.3接口的综合案例(重点)
示例:
ClassManager
package com.itheima.d9_interface_demo;
import java.util.ArrayList;
public class ClassManager {
private ArrayList<Student> students = new ArrayList<>();
private StudentOperator studentOperator=new StudentOperatorImpl2();
public ClassManager() {
students.add(new Student("迪丽热巴", '女', 99));
students.add(new Student("古力娜扎", '女', 100));
students.add(new Student("波波维奇", '男', 60));
students.add(new Student("科比曼巴", '男', 23));
}
//打印全部学生的信息
public void printInfo(){
studentOperator.printAllInfo(students);
}
//打印全部学生的平均分
public void printScore(){
studentOperator.printAverageScore(students);
}
}
Student
package com.itheima.d9_interface_demo;
public class Student {
private String name;
private char sex;
private double score;
public Student() {
}
public Student(String name, char sex, double score) {
this.name = name;
this.sex = sex;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
StudentOperator
package com.itheima.d9_interface_demo;
import java.util.ArrayList;
public interface StudentOperator {
void printAllInfo(ArrayList<Student> students);
void printAverageScore(ArrayList<Student> students);
}
StudentOperatorImpl1
package com.itheima.d9_interface_demo;
import java.util.ArrayList;
public class StudentOperatorImpl1 implements StudentOperator{
@Override
public void printAllInfo(ArrayList<Student> students) {
System.out.println("------------全班全部学生信息如下-------------");
for (int i = 0; i < students.size(); i++) {
System.out.println("第"+i+"号学生:");
Student s=students.get(i);
System.out.println("姓名:"+s.getName()+",性别:"+s.getSex()+",成绩:"+s.getScore());
}
System.out.println("------------------------------");
}
@Override
public void printAverageScore(ArrayList<Student> students) {
double allScore=0.0;
for (int i = 0; i < students.size(); i++) {
Student s=students.get(i);
allScore+=s.getScore();
}
System.out.println("平均分"+(allScore)/students.size());
}
}
StudentOperatorImpl2
package com.itheima.d9_interface_demo;
import java.util.ArrayList;
public class StudentOperatorImpl2 implements StudentOperator{
@Override
public void printAllInfo(ArrayList<Student> students) {
int count1=0,count2=0;
System.out.println("------------全班全部学生信息如下-------------");
for (int i = 0; i < students.size(); i++) {
System.out.println("第"+i+"号学生:");
Student s=students.get(i);
System.out.println("姓名:"+s.getName()+",性别:"+s.getSex()+",成绩:"+s.getScore());
if(s.getSex()=='男'){
count1++;
}else {
count2++;
}
}
System.out.println("男生人数是:"+count1+",女生人数是"+count2);
System.out.println("班级总人数是:"+students.size());
System.out.println("------------------------------");
}
@Override
public void printAverageScore(ArrayList<Student> students) {
double allScore=0.0;
double max=students.get(0).getScore();
double min=students.get(0).getScore();
for (int i = 0; i < students.size(); i++) {
Student s=students.get(i);
if(s.getScore()>max){
max=s.getScore();
}
if (s.getScore()<min){
min=s.getScore();
}
allScore+=s.getScore();
}
System.out.println("学生的最高分是:"+max);
System.out.println("学生的最低分是:"+min);
System.out.println("平均分"+(allScore-min-max)/(students.size()-2));
}
}
Test
package com.itheima.d9_interface_demo;
public class Test {
public static void main(String[] args) {
//目标:完成学生信息管理的案例
ClassManager c=new ClassManager();
c.printInfo();
c.printScore();
}
}
2.4.4接口的其他细节:JDK8开始,接口中新增的三种方法
JDK8开始,接口新增了三种形式的方法:
JDK8开始,接口中为啥要新增这些方法?
- 增强了接口的能力,更便于项目的扩展和维护。
示例:
A
package com.itheima.d10_interface_jdk8;
public interface A {
//1.默认方法:必须使用default修饰,默认会被public修饰
//实例方法:对象的方法,必须使用实现类的对象来访问
default void test1(){
System.out.println("==默认方法==");
test2();//在一般方法中访问私有方法
}
//2.私有方法:必须使用private修饰(Jdk9开始支持)
private void test2(){
System.out.println("==私有方法==");
}
//3.静态方法:必须使用static修饰,默认会被public修饰
static void test3(){
System.out.println("==静态方法==");
}
}
B
package com.itheima.d10_interface_jdk8;
public class B implements A{
}
Test
package com.itheima.d10_interface_jdk8;
public class Test {
public static void main(String[] args) {
B b=new B();
b.test1();
A.test3();
}
}
2.4.5接口的其他细节:接口的多继承、使用接口的注意事项【了解】
接口多继承的作用
- 便于实现类去实现。
示例
Test
package com.itheima.d11_interface_attention;
public class Test {
public static void main(String[] args) {
//目标:理解接口的多继承
}
}
interface A{
void testA();
}
interface B{
void testB();
}
interface C{
void testC();
}
//接口是多继承的
interface D extends C,B,A{
}
class E implements D{
@Override
public void testA() {
}
@Override
public void testB() {
}
@Override
public void testC() {
}
}
接口其他注意事项(了解)
- 一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。
- 一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。
- 一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。
- 一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
3.面向对象高级三
3.1内部类
- 是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。
- 场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。
内部类有四种形式
1.成员内部类
2.静态内部类
3.局部内部类
4.匿名内部类
3.1.1成员内部类(了解)
- 就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法。
注意: JDK16之前,成员内部类中不能定义静态成员,JDK16开始也可以定义静态成员了
创建对象的格式:
成员内部类中访问其他成员的特点:
1、和前面学过的实例方法一样,成员内部类的实例方法中,同样可以直接访问外部类的实例成员、静态成员。
2、可以在成员内部类的实例方法中,拿到当前外部类对象,格式是:外部类名.this。
示例:
Test
package com.itheima.d1_inner_class1;
public class Test {
public static void main(String[] args) {
//了解成员内部类和其特点
Outer.Inner in = new Outer().new Inner();
in.test();
}
}
Outer
package com.itheima.d1_inner_class1;
public class Outer {
private int age=99;
public static String a="Hello";
//成员内部类
public class Inner{
private String name;
private int age=88;
public static String schoolName;//jdk16开始支持定义静态成员
public void test(){
//可以访问外部类的私有、公有成员变量
System.out.println(age);
System.out.println(a);
int age=66;
System.out.println(age);//66
System.out.println(this.age);//88
System.out.println(Outer.this.age);//99
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static String getSchoolName() {
return schoolName;
}
public static void setSchoolName(String schoolName) {
Inner.schoolName = schoolName;
}
}
}
3.1.2静态内部类(了解)
- 有static修饰的内部类,属于外部类自己持有
创建对象的格式:
静态内部类中访问外部类成员的特点 - 可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。
示例:
Outer
package com.itheima.d2_inner_class2;
public class Outer {
private int age;
public static String schoolname;
//静态内部类
public static class Inner{
private String name;
public static int a;
public void test(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static int getA() {
return a;
}
public static void setA(int a) {
Inner.a = a;
}
public static void test2(){
System.out.println(schoolname);
//System.out.println(age);不能直接访问外部类实例成员
}
}
}
Test
package com.itheima.d2_inner_class2;
public class Test {
public static void main(String[] args) {
//目标:了解静态内部类
Outer.Inner in=new Outer.Inner();
}
}
3.1.3局部内部类(了解)
-局部内部类是定义在在方法中、代码块中、构造器等执行体中。
3.1.4匿名内部类(重点)
3.1.4.1认识匿名内部类
匿名内部类
- 就是一种特殊的局部内部类;所谓匿名,指的是程序员不需要为这个类声明名字
- 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
- 作用:用于更方便的创建一个子类对象。
示例:
Test
package com.itheima.d3_inner_class3;
public class Test {
public static void main(String[] args) {
//目标:人士匿名的内部类,并掌握其作用
// Animal a= new Cat();
// a.cry();
//1.把这个匿名内部类编译成一个子类,然后立即创建一个子类对象出来
Animal a= new Animal(){
@Override
public void cry(){
System.out.println("猫咪喵喵地叫");
}
};
a.cry();
}
}
abstract class Animal{
public abstract void cry();
}
/*
class Cat extends Animal{
@Override
public void cry(){
System.out.println("猫咪喵喵地叫");
}
}*/
3.1.4.2匿名内部类使用场景
- 通常作为一个参数传输给方法
需求:猫、狗参加游泳比赛
示例:
Test2
package com.itheima.d3_inner_class3;
public class Test2 {
public static void main(String[] args) {
//目标:掌握匿名的常见使用场景。
/* Swimming s1=new Swimming() {
@Override
public void swim() {
System.out.println("狗游得飞快~~~");
}
};
go(s1);
}*/
go(new Swimming() {
@Override
public void swim() {
System.out.println("狗游得飞快~~~");
}
});
}
//设计一个方法,可以接收swimming接口的一切实现类对象进来参加游泳比赛。
public static void go(Swimming s){
System.out.println("开始-------------------------------");
s.swim();
}
}
//猫和狗都要参加游泳比赛
interface Swimming{
void swim();
}
真是使用场景
示例:
Test
package com.itheima.d5_inneer_class5;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLOutput;
public class Test {
public static void main(String[] args) {
//拓展:搞清楚匿名内部类在开发中的真是使用场景
//GUI编程
//1.创建窗口
JFrame win=new JFrame("登录界面");
JPanel panel=new JPanel();
win.add(panel);
JButton btn=new JButton("登录");
panel.add(btn);
//给按钮绑定单机事件监听器
/* btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(win,"登录一下");
}
});*/
//最终的核心目的:简化代码
btn.addActionListener(e->JOptionPane.showMessageDialog(win,"登录一下"));
win.setSize(400,400);
win.setLocationRelativeTo(null);//居中
win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
win.setVisible(true);//设置可见
}
}
3.2枚举
3.2.1认识枚举
枚举
- 枚举是一种特殊类
注意: - 枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开。
- 这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
枚举类的特点:
- == 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。==
- 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
- 枚举都是最终类,不可以被继承。
- 枚举类中,从第二行开始,可以定义类的其他各种成员。
- 编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法。
示例:
A
package com.itheima.d6_enum;
public enum A {
//注意,枚举的第一行必须罗列的是枚举对象的名字
X,Y,Z;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
B
package com.itheima.d6_enum;
//拓展:抽象枚举
public enum B {
X(){
@Override
public void go() {
}
},Y("张三"){
@Override
public void go() {
System.out.println(getName()+"在跑~~");
}
};
private String name;
//枚举构造器只能是私有的
B() {
}
B(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void go();
}
Test
package com.itheima.d6_enum;
public class Test {
public static void main(String[] args) {
//目标:认识枚举
A a1=A.X;
//1、枚举类的构造器都是私有的,不能对外创建对象
// A a=new A();
//2、枚举类的第一行都是常量,记住的是枚举类的对象
A a2=A.Y;
//3、枚举类提供了一些额外的API
A[] as =A.values();//拿到全部对象
A a3=A.valueOf("Z");//根据常量名得到枚举对象
System.out.println(a3.name());//Z
System.out.println(a3.ordinal());//索引
System.out.println("-------------------");
B y=B.Y;
y.go();
}
}
3.2.1枚举的常见应用场景
枚举的常见应用场景:
- 用来表示一组信息,然后作为参数进行传输。
选择定义一个一个的常量来表示一组信息,并作为参数传输 - 参数值不受约束。
选择定义枚举表示一组信息,并作为参数传输 - 代码可读性好,参数值得到了约束,对使用者更友好,建议使用
示例:
Constant
package com.itheima.d7_enum2;
public class Constant {
public static final int BOY=0;
public static final int GIRL=1;
}
Constant2
package com.itheima.d7_enum2;
public enum Constant2 {
BOY,GIRL
}
Test
package com.itheima.d7_enum2;
public class Test {
public static void main(String[] args) {
//目标:掌握枚举的应用场景,做信息标志和分类
check(Constant2.BOY);
}
public static void check(Constant2 sex){
//switch天生知道枚举可以做信息标和分类,不需要前缀
switch (sex){
case BOY:
System.out.println("展示一些美女图,游戏信息~");
break;
case GIRL:
System.out.println("展示一些帅哥图,一些土豪信息");
}
}
/* public static void check(int sex){
switch (sex){
case Constant.BOY:
System.out.println("展示一些美女图,游戏信息~");
break;
case Constant.GIRL:
System.out.println("展示一些帅哥图,一些土豪信息");
}
}*/
}
3.3泛型
3.3.1认识泛型
- 定义类、接口、方法时,同时声明了一个或者多个类型变量(如:),称为泛型类、泛型接口,泛型方法、它们统称为泛型。
- 作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
- == 泛型的本质:把具体的数据类型作为参数传给类型变量。==
示例:
Test1
package com.itheima.d5_generics;
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) {
//目标:认识泛型
ArrayList list=new ArrayList();
list.add("java1");
list.add("java2");
list.add("java3");
//list.add(new Cat());
for (int i = 0; i < list.size(); i++) {
String e = (String) list.get(i);//必须强转,但是对Cat的实例强转会出错,即使没有其他类型,实际上都是字符串,也得强转
System.out.println(e);
}
System.out.println("------------------------------");
// ArrayList<String> list1=new ArrayList<String>();
ArrayList<String> list1=new ArrayList<>();//从jdk1.7开始,后面的数据类型可以不声明
list1.add("python1");
list1.add("python2");
list1.add("python3");
for (int i = 0; i < list1.size(); i++) {
String e=list1.get(i);
System.out.println(e);
}
}
}
class Cat{
}
3.3.2泛型类
泛型类
- 注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V等
示例:
Animal
package com.itheima.d8_generics_class;
public class Animal {
}
Cat
package com.itheima.d8_generics_class;
public class Cat extends Animal{
}
Dog
package com.itheima.d8_generics_class;
public class Dog extends Cat{
}
MyArrayList
package com.itheima.d8_generics_class;
//泛型类
public class MyArrayList<E> {
Object[] arr=new Object[10];
private int size;
public boolean add(E e){
arr[size++]=e;
return true;
}
public E get(int index){
return (E)arr[index];
// return arr[index];不能直接返回Object类
}
}
MyClass2
package com.itheima.d8_generics_class;
public class MyClass2<E,T> {
public void put(E e,T t){
}
}
MyClass3
package com.itheima.d8_generics_class;
public class MyClass3 <E extends Animal>{
}
Test
package com.itheima.d8_generics_class;
public class Test {
public static void main(String[] args) {
//目标:掌握泛型类的定义和使用
MyArrayList<String> list =new MyArrayList();
list.add("Java1");
list.add("Java2");
list.add("Java3");
String ele =list.get(1);
System.out.println(ele);
MyClass2<Cat,String> c2=new MyClass2<>();
MyClass3<Animal> c3=new MyClass3<>();
MyClass3<Cat> c4=new MyClass3<>();
MyClass3<Dog> c5=new MyClass3<>();//限定送进来的必须是Animal或其子类(孙类也行)
}
}
3.3.3泛型接口
泛型接口
- 注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V等
示例:
Data
package com.itheima.d9_generics_interface;
import java.util.ArrayList;
//泛型接口同样可以继承某一类型
public interface Data <T extends Object>{
void add(T t);
ArrayList<T> getByName(String name);
}
Student
package com.itheima.d9_generics_interface;
public class Student {
}
StudentData
package com.itheima.d9_generics_interface;
import java.util.ArrayList;
public class StudentData implements Data<Student>{
@Override
public void add(Student student) {
}
@Override
public ArrayList<Student> getByName(String name) {
return null;
}
}
Teacher
package com.itheima.d9_generics_interface;
public class Teacher {
}
TeacherData
package com.itheima.d9_generics_interface;
import java.util.ArrayList;
public class TeacherData implements Data<Teacher>{
@Override
public void add(Teacher teacher) {
}
@Override
public ArrayList<Teacher> getByName(String name) {
return null;
}
}
Test
package com.itheima.d9_generics_interface;
public class Test {
public static void main(String[] args) {
//目标:掌握泛型接口的定义和使用。
//场景:系统需要处理学生和老师的数据,需要提供2个功能:保存对象数据。根据名称查询数据。
}
}
3.3.4泛型方法、通配符、上下限
泛型方法
通配符
- 就是“?”,可以在“使用泛型”的时候代表一切类型;E T K V是在定义泛型的时候使用。
泛型的上下限:
- 泛型上限:?extends Car:?能接收的必须是Car或者其子类。
- 泛型下限:?super Car:?能接收的必须是Car或者其父类。
示例:
BENZ
package com.itheima.d10_generics_method;
public class BENZ extends Car{
}
BMW
package com.itheima.d10_generics_method;
public class BMW extends Car{
}
Car
package com.itheima.d10_generics_method;
public class Car {
}
Dog
package com.itheima.d10_generics_method;
public class Dog {
}
Test
package com.itheima.d10_generics_method;
import com.itheima.d6_enum.A;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
//目标:掌握泛型方法的定义和使用
String s= test("java");//T可以是任何类型,即所谓的泛型
System.out.println(s);
Dog d=test(new Dog());
System.out.println(d);
//需求:所有的汽车可以一起参加比赛。
ArrayList<Car> cars=new ArrayList<>();
cars.add(new BMW());
cars.add(new BENZ());
go(cars);
ArrayList<BMW> bmws=new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
go(bmws);
ArrayList<BENZ> benzs=new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
go(benzs);
//重点:ArrayList<BENZ>和ArrayList<Car>没有继承关系,不相干,想用go必须用泛型
/* ArrayList<Dog> dogs=new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
go(dogs);报错,因为Dog不是Car的子类*/
}
//?通配符,在使用泛型的时候可以代表一切类型 ?extends Car(上限) ?super Car(下限)
public static void go(ArrayList<?extends Car> cars){
}
/* public static <T extends Car> void go(ArrayList<T> cars){
}*/
//泛型方法
public static <T> T test(T t){
return t;
}
}
3.3.5 泛型的注意事项:擦除问题、基本数据类型问题
- 泛型是工作在编译阶段的,一旦程序编译成class:文件,class文件中就不存在泛型了,这就是泛型擦除。
- 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
示例:
Test
package com.itheima.d11_generics_attention;
import com.itheima.d6_enum.A;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
//目标:理解泛型的注意事项。
//1、泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
ArrayList<String> list=new ArrayList<>();
list.add("java1");
list.add("java2");
list.add("java3");
String rs =list.get(2);//反编译后发现其实还是帮你强转了
System.out.println(rs);
//2.泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
//ArrayList<int> list1 =new ArrayList<>();不支持
//ArrayList<double> list2 =new ArrayList<>();不支持
ArrayList<Integer> list1=new ArrayList<>();
list1.add(12);
ArrayList<Double> list2=new ArrayList<>();
list2.add(12.3);
}
}
3.4常用API(一)
3.4.1API概述
什么是API?
- API(Application Programming interface):应用程序编程接口
- 就是java帮我们已经写好一些程序,如:类、方法等,我们直接拿过来用就可以解决一些问题。
常用API
3.4.2Object
Object:类的作用:
- Object类是Java中所有类的祖宗类,因此,Java中所有类的对象都可以直接使用Object类中提供的一些方法。
Object类的常见方法
- toString存在的意义:toString()方法存在的意义就是为了被子类重写,以便返回对象具体的内容。
- equals存在的意义:直接比较两个对象的地址是否相同完全可以用"==”替代equals,equals存在的意义
就是为了被子类重写,以便子类自己来定制比较规则(比如比较对象内容)。
示例:
Student
package com.itheima.d12_api_object;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写equals方法,比较两个对象的内容,一样就返回true
//比较者:s2 == this (调用者)
//被比较者:s1 == o
@Override
public boolean equals(Object o) {
//1.判断两者地址是否一样,是就返回true
if (this == o) return true;
//2.判断o是null直接返回false或者双方类型不一样,直接false
// Student.class(比较者的类型)!=o.class(被比较者的类型)
if (o == null || getClass() != o.getClass()) return false;
//3.o不是null,且o一定是学生类型的对象,开始比较内容了!
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
Test
package com.itheima.d12_api_object;
public class Test {
public static void main(String[] args) {
//目标:掌握Object类提供的常见方法
Student s1=new Student("赵云",30);
// System.out.println(s1.toString());可以直接输出s1,结果一样
System.out.println(s1);
Student s2=new Student("赵云",30);
System.out.println(s2.equals(s1));//equal本身也是比较地址,但是更多是让我们重写比较
System.out.println(s2==s1);//直接比较地址
}
}
Object类提供的对象克隆方法
- 当某个对象调用这个方法时,这个方法会复制一个一模一样的新对象返回。
浅克隆
- 拷贝出的新对象,与原对象中的数据一模一样(引用类型拷贝的只是地址)
深克隆
- 对象中基本类型的数据直接拷贝
- 对象中的字符串数据拷贝的还是地址
- 对象中还包含的其他对象,不会拷贝地址,会创建新对象。
示例:
Test2
package com.itheima.d12_api_object;
public class Test2 {
public static void main(String[] args) throws CloneNotSupportedException {
//目标:掌握Object类提供的对象克隆的方法。
//1、protected Object clone():对象克隆。
User u1 =new User(1,"张三","1234",new double[]{99.0,31.4});
User u2=(User) u1.clone();// clone本身会返回一个Object,但我们知道克隆出来的肯定是User,强转一下
System.out.println(u1.getId());
System.out.println(u1.getUsername());
System.out.println(u1.getPassword());
System.out.println(u1.getScores());
System.out.println(u2.getId());
System.out.println(u2.getUsername());
System.out.println(u2.getPassword());
System.out.println(u2.getScores());
System.out.println(u2.equals(u1));
}
}
User
package com.itheima.d12_api_object;
//Cloneable是一个标记接口
//这是一种规则
public class User implements Cloneable{
private int id;
private String username;
private String password;
private double[] scores;
public User() {
}
public User(int id, String username, String password, double[] scores) {
this.id = id;
this.username = username;
this.password = password;
this.scores = scores;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//super去调用父类Object中的clone方法;
User u2=(User) super.clone();
u2.scores=u2.scores.clone();//新建数组,实现深克隆
//浅克隆只需要 return super.clone();这一行就行
return u2;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public double[] getScores() {
return scores;
}
public void setScores(double[] scores) {
this.scores = scores;
}
}
3.4.3Objects
- Objects是一个工具类,提供了很多操作对象的静态方法给我们使用。
示例
Test
package com.itheima.d13_api_objects;
import java.util.Objects;
public class Test {
public static void main(String[] args) {
//目标:掌握Objects类提供的常见方法。
String s1 =null;
String s2 ="itheima";
//System.out.println(s1.equals(s2));有null会报错,空指针异常
System.out.println(Objects.equals(s1, s2));//更安全
System.out.println(Objects.isNull(s1));//true
System.out.println(s1==null);
System.out.println(Objects.isNull(s2));//false
System.out.println(s2==null);//其实代码都一样,调用比较更有逼格
System.out.println(Objects.nonNull(s1));//false
System.out.println(Objects.nonNull(s2));//true
}
}
3.4.4包装类
- 包装类就是把基本类型的数据包装成对象。
自动装箱:基本数据类型可以自动转换为包装类型。 自动拆箱:包装类型可以自动转换为基本数据类型
包装类的其他常见操作
-
可以把基本类型的数据转换成字符串类型。
-
可以把字符串类型的数值转换成数值本身对应的数据类型。
示例
Test
package com.itheima.d14_integer;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
//目标:掌握包装类的使用
//Integer a1=new Integer(12);过时
Integer a2=Integer.valueOf(12);
System.out.println(a2);
//自动装箱:可以自动把基本类型的数据转换成对象
Integer a3=12;
// 自动拆箱:可以自动把包装类型的对象转换成对应的基本数据类型。
int a4=a3;
//泛型和集合不支持基本数据类型,只能支持引用数据类型。
//ArrayList<int>list =new ArrayList<>();
ArrayList<Integer> list =new ArrayList<>();
list.add(12);//自动装箱
int rs=list.get(0);//自动拆箱
System.out.println("----------------------------------------------");
//1.把基本类型的数据转换为字符串、
Integer a=23;
String rs1=Integer.toString(a);//"23"
System.out.println(rs1 + 1);//"231"
String rs2=a.toString();//Object类的toString "23"
System.out.println(rs2 + 1);//"231"
String rs3= a+"";
System.out.println(rs3 + 1);//"231"
//2.把字符串的数值转换成对应的基本类型
String ageStr ="29";//一定要是对应的数值类型,29a,29.2都不行
//int ageI=Integer.parseInt(ageStr);//29,不建议这么用
int ageI=Integer.valueOf(ageStr);//29
System.out.println(ageI+1);//30
String scoreStr="99.5";
//double score=Double.parseDouble(scoreStr);
double score=Double.valueOf(scoreStr);
System.out.println(score+0.5);
}
}
3.4.5 StringBuild与StringBuffer
- StringBuilder代表可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,就是用来操作字符串的。
- 好处:StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁。
为什么操作字符串建议使用StringBuilder,而不用原来学过的String?
- 对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuidler,效率更高!
- 注意:如果操作字符串较少,或者不需要操作,以及定义字符串变量,还是建议用String。
StringBufferStringBuilder
注意:
- StringBuffer的用法与StringBuilder是一模一样的
- 但StringBuilder是线程不安全的StringBuffer是线程安全的
示例
Test1
package com.itheima.d15_stringbuild;
public class Test1 {
public static void main(String[] args) {
//目标:搞清楚StringBuilder的用法和作用。
//StringBuilder s = new StringBuilder();//s "
StringBuilder s = new StringBuilder("itheima");//s "itheima"
//1、拼接内容
s.append(12);
s.append("黑马");
s.append(true);
System.out.println(s);//itheima12黑马true
//支持链式编程
s.append(666).append("黑马2");
System.out.println(s);//itheima12黑马true666黑马2
//2.反转操作
s.reverse();
System.out.println(s);//2马黑666eurt马黑21amiehti
//3.返回字符串长度
System.out.println(s.length());//21
//4.把StringBuilder对象转换成String类型
String rs=s.toString();
System.out.println(rs);//2马黑666eurt马黑21amiehti
}
}
Test2
package com.itheima.d15_stringbuild;
public class Test2 {
public static void main(String[] args) {
//目标:掌握StringBuilder的好处。
//需求:要拼接100万次abc
//先用String测试看看性能
/*
String rs ="";
for(int i=1;i<=1000000;i++){
rs +="abc";
}
System.out.println(rs);
太慢了,半天出不来
*/
//使用StringBuilder演示
StringBuilder sb=new StringBuilder();
for (int i = 0; i < 1000000; i++) {
sb.append("abc");
}
System.out.println(sb);
}
}
Test3
package com.itheima.d15_stringbuild;
public class Test3 {
public static void main(String[] args) {
//目标:完成遍历数组内容,并拼接成指定格式的案例。
System.out.println(getArrayData(new int[]{11, 22, 33}));
}
public static String getArrayData(int[] arr){
//1、判断arr是否为null
if (arr==null){
return null;
}
//2.arr数组对象存在,arr[11,22,33]
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("]");
return sb.toString();
}
}
3.4.6 StringJoiner
- JDK8开始才有的,跟StringBuilder一样,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的。
- 好处:不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁
示例
package com.itheima.d16_stringjoiner;
import java.util.StringJoiner;
public class Test {
public static void main(String[] args) {
//目标:掌握StringJoiner的使用
// StringJoiner s=new StringJoiner(",");//间隔符
StringJoiner s=new StringJoiner(",","[","]");
s.add("java1");
s.add("java2");
s.add("java3");
s.add("java4");
System.out.println(s);//[java1,java2,java3,java4]
}
}
3.5常用API(二)
3.5.1 Math、System、Runtime
Math
- 代表数学,是一个工具类,里面提供的都是对数据进行操作的一些静态方法。
System - System代表程序所在的系统,也是一个工具类。
System类提供的常见方法
时间毫秒值 - 指的是从1970年1月1日 00:00:00走到此刻的总的毫秒数,应该是很大的。1s=1000ms
为啥选择“1970年1月1日00:00:00”作为时间的起点?
1969年8月,贝尔实验室的程序员肯汤普逊利用妻儿离开一个月的机会,开始着手创造一个全新的革命性的操作
系统,他使用B编译语言在老旧的PDP-7机器上开发出了Uix的一个版本。随后,汤普逊和同事丹尼斯里奇改进了B
语言,开发出了C语言,重写了UNX.
1970年1月1日算C语言的生日
Runtime
- 代表程序所在的运行环境
- Runtime是一个单例类
Runtime类提供的常见方法
示例
MathTest
package com.itheima.math;
public class MathTest {
public static void main(String[] args) {
//目标:了解下Math类提供的常见方法。
//1、public static int abs(inta):取绝对值(拿到的结果一定是正数)
//public static double abs(double a)
System.out.println(Math.abs(-13));//13
System.out.println(Math.abs(123));//123
System.out.println(Math.abs(-3.14));//-3.14
//2、public static double ceil(double a):向上取整
System.out.println(Math.ceil(4.0000001));//5.0
System.out.println(Math.ceil(4.0));//4.0
//3、public static double floor(double a):向下取整
System.out.println(Math.floor(4.999999999999));//4.o
System.out.println(Math.floor(4.0));//4.0
//4、public static long round(double a):四舍五入
System.out.println(Math.round(3.4999999999));//3
System.out.println(Math.round(3.5000000001));//4
//5、public static int max(inta,intb):取较大值
//public static int min(inta,intb):取较小值
System.out.println(Math.max(10, 20));//20
System.out.println(Math.min(10, 20));//10
//6、public static double pow(double a,double b):取次方
System.out.println(Math.pow(2, 3));//2的3次方 8
System.out.println(Math.pow(3, 2));//3的2次方 9
//7、public static double random():取随机数[0.0,1.0)(包前不包后)
System.out.println(Math.random());
}
}
RuntimeTest
package com.itheima.math;
import java.io.IOException;
public class RuntimeTest {
public static void main(String[] args) throws IOException, InterruptedException {
//目标:了解Runtime的几个常见方法
//1、public static Runtime getRuntime()返回与当前Java应用程序关联的运行时对象。
Runtime r=Runtime.getRuntime();
//2、public void exit(int status)终止当前运行的虚拟机,该参数用作状态代码;按照惯例,非零状态代码表示异常终止。
//r.exit(0); System的exit也是调用runtime的exit
//3.public int availableProcessors() 获取虚拟机能够使用的处理器数
System.out.println(r.availableProcessors());
//4、public long totalMemory()返回Java虚拟机中的内存总量。
System.out.println(r.totalMemory()/1024.0/1024.0+"MB");//1024=1k 1024*1024=1M
//5、public long freeMemory()返回Java虚拟机中的可用内存量
System.out.println(r.freeMemory()/1024.0/1024.0+"MB");
//6、public Process exec(String command)启动某个程序,并返回代表该程序的对象。
// r.exec("D:\\download\\CloudMusic\\cloudmusic.exe");
Process p= r.exec("QQ");//前提是路径添加到Path中
Thread.sleep(5000);//程序在这里停5秒
p.destroy();//关闭程序
}
}
SystemTest
package com.itheima.math;
public class SystemTest {
public static void main(String[] args) {
//目标:了解下System类的常见方法。
//1. public static void exit(int status);
//终止当前运行的Java虚拟机。
//该参数用作状态代码;按照惯例,非零状态代码表示异常终止。
//System.exit(0);//人为中止虚拟机(不要使用)
//2.public static long currentTimeMillis();
//获取当前系统的时间
//返回的是long类型的时间毫秒值:指的是从1970-1-1 0:0:0开始走到此刻的总的毫秒值,1s=1000ms
long time =System.currentTimeMillis();
System.out.println(time);
for (int i = 0; i < 1000000; i++) {
System.out.println("输出了:"+i);
}
long time2=System.currentTimeMillis();
System.out.println("花了"+(time2-time)/1000.0+"s");
}
}
3.5.2BigDecimal
- 用于解决浮点型运算时,出现结果失真的问题。
BigDecimall的常见构造器、常用方法
示例
BigDecimalDemo
package com.itheima.bigDecimal;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalDemo1 {
public static void main(String[] args) {
//目标:掌握BigDecimal的使用,用于解决浮点型运算时出现结果失真的问题,
double a=0.1;
double b=0.2;
double c=a+b;
System.out.println(c);//0.30000000000000004
System.out.println("--------------------------------------");
//1.把他们变成字符串封装成BigDecimal对象来运算
/* BigDecimal a1=new BigDecimal(Double.toString(a));
BigDecimal b1=new BigDecimal(Double.toString(b));
可以优化写法
*/
BigDecimal a1=BigDecimal.valueOf(a);//封装好了上面注释的写法
BigDecimal b1=BigDecimal.valueOf(b);
BigDecimal c1=a1.add(b1);//加
/* BigDecimal c1=a1.subtract(b1);减
BigDecimal c1=a1.multiply(b1);乘
BigDecimal c1=a1.divide(b1)除;
*/
System.out.println(c1);//0.3
BigDecimal i=BigDecimal.valueOf(0.1);
BigDecimal j=BigDecimal.valueOf(0.3);
BigDecimal k=i.divide(j,2, RoundingMode.HALF_UP);//除法,两位小数,四舍五入
double rs=k.doubleValue();
System.out.println(rs);//0.33dd
}
}
3.5.3JDK8之前传统的日期、时间
3.5.3.1Date
- 代表时间和日期
3.5.3.2SimpleDateFormat
- 代表简单日期格式化,可以用来把日期对象、时间毫秒值格式化成我们想要的形式。
时间格式的常见符号
SimpleDateFormat解析字符串时间成为日期对象
示例
TestDate
package com.itheima.time;
import com.itheima.d9_generics_interface.Data;
import java.util.Date;
public class TestDate {
public static void main(String[] args) {
//目标:掌握Date日期类的使用
//1.创建一个Date的对象,代表系统当前时间信息
Date d=new Date();
System.out.println(d);
//2.拿到时间毫秒值。
long time =d.getTime();
System.out.println(time);
//3.把时间毫秒值转换成日期对象,2s之后的时间是多少
time+=2000;
Date d2 = new Date(time);
System.out.println(d2);
//直接把日期对象的时间通过setTime方法进行修改
Date d3 = new Date();
d3.setTime(time);
System.out.println(d3);
}
}
TestSimpleDateFormat
package com.itheima.time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestSimpleDateFormat {
public static void main(String[] args) throws ParseException {
//目标:掌握SimpleDateFormat的使用。
//1、准备一些时间
Date d =new Date();
System.out.println(d);//Fri Mar 29 18:13:14 AWST 2024
Long time = d.getTime();
System.out.println(time);//1711707194177
//2、格式化日期对象,和时间毫秒值
SimpleDateFormat f= new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
String rs=f.format(d);
System.out.println(rs);//2024年03月29日 18:13:14 周五 下午
String rs2=f.format(time);
System.out.println(rs2);//2024年03月29日 18:13:14 周五 下午
System.out.println("-----------------------------------------");
//目标:掌握SimpleDateFormat解析字符串时间成为日期对象。
String datestr="2022-12-12 12:12:11";
//1.创建简单日期格式化对象,指定的时间格式必须与被解析的时间格式一模一样,否则程序会出bug
SimpleDateFormat f2=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d2 =f2.parse(datestr);
System.out.println(d2);//Mon Dec 12 12:12:11 AWST 2022
}
}
3.5.3.3练习:秒杀活动
示例:
Demo
package com.itheima.time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo {
public static void main(String[] args) throws ParseException {
//目标:完成秒杀案例。
//1、把开始时间、结束时间、小贾下单时间、小皮下单时间拿到程序中来。
String start="2023年11月11日 0:0:0";
String end="2023年11月11日 0:10:0";
String xj="2023年11月11日 0:01:18";
String xp="2023年11月11日 0:10:57";
//2.把字符串时间解析成日期对象
SimpleDateFormat s = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date startDt=s.parse(start);
Date endDt=s.parse(end);
Date xjDt=s.parse(xj);
Date xpDt=s.parse(xp);
//3.开始判断小皮和小贾是否秒杀成功了。
//把日期对象转换成时间毫秒值来判断
long startTime = startDt.getTime();
long endTime = endDt.getTime();
long xjTime = xjDt.getTime();
long xpTime = xpDt.getTime();
if(xjTime>=startTime&&xjTime<=endTime){
System.out.println("小贾您秒杀成功了~~");
}else {
System.out.println("小贾您秒杀失败了~~");
}
if(xpTime>=startTime&&xpTime<=endTime){
System.out.println("小皮您秒杀成功了~~");
}else {
System.out.println("小皮您秒杀失败了~~");
}
}
}
3.5.3.4Calendar
Calendar
- 代表的是系统此刻时间对应的日历。
- 通过它可以单独获取、修改时间中的年、月、日、时、分、秒等。
Calendar日历类的常见方法
示例
TestCalendar
package com.itheima.time;
import java.util.Calendar;
import java.util.Date;
public class TestCalendar {
public static void main(String[] args) {
//目标:学握Calendar的使用和特点。
//1、得到系统此刻时阿对应的日历对象。
Calendar now = Calendar.getInstance();
System.out.println(now);
/* java.util.GregorianCalendar[time=1711717009607,areFieldsSet=true,
areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Australia/Perth",
offset=28800000,dstSavings=0,useDaylight=false,transitions=20,lastRule=null],firstDayOfWeek=1,
minimalDaysInFirstWeek=1,ERA=1,YEAR=2024,MONTH=2,WEEK_OF_YEAR=13,WEEK_OF_MONTH=5,DAY_OF_MONTH=29,
DAY_OF_YEAR=89,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=5,AM_PM=1,HOUR=8,HOUR_OF_DAY=20,MINUTE=56,
SECOND=49,MILLISECOND=607,ZONE_OFFSET=28800000,DST_OFFSET=0]*/
//2.获取日历中的某个值
int year=now.get(Calendar.YEAR);
System.out.println(year);
System.out.println(now.get(Calendar.MONTH));
//3.拿到日历中记录的日期对象
Date d=now.getTime();
System.out.println(d);
//4.拿到时间毫秒值
long time =now.getTimeInMillis();
System.out.println(time);
//5.修改日历中的某个信息
now.set(Calendar.MONTH,9);//修改月份为10月(从0开始)
now.set(Calendar.DAY_OF_YEAR,125); //修改成一年中的第125天
System.out.println(now);
//6.为某个信息增加或者减少多少
now.add(Calendar.DAY_OF_YEAR,100);
now.add(Calendar.DAY_OF_YEAR,-10);
now.add(Calendar.DAY_OF_MONTH,6);
now.add(Calendar.HOUR,12);
System.out.println(now);
}
}
3.5.4JDK8之前传统的日期、时间
3.5.4.1为什么要学JDK8新增的时间?
JDK8新增的时间
LocalDate:年、月、日
LocalTime:时、分、秒
LocalDateTime:年、月、日时、分、秒
ZoneId:时区
ZonedDateTime:带时区的时间
Instant:时间戳/时间线
DateTimeFormatter:用于时间的格式化和解析
Duration:时间间隔(时、分、秒,纳秒)
Period:时间间隔(年,月,日)
示例
Test
package com.itheima.jdk8_time;
import java.util.Calendar;
import java.util.Date;
/*
目标:搞清楚为什么要用JDK8开始新增的时间类。
*/
public class Test {
public static void main(String[] args) {
//传统的时间类(Date、SimpleDateFormat、Calendar)存在如下问题:
//1、设计不合理,使用不方便,很多都被淘汰了。
Date d = new Date();
System.out.println(d.getYear() + 1900);//getYear拿到的是当前年份减去1900
Calendar c= Calendar.getInstance();
int year =c.get(Calendar.YEAR);//麻烦,还要自己记字段
System.out.println(year);
//2、都是可变对象,修改后会丢失最开始的时间信息。
//3、线程不安全。
//4、不能精确到纳秒,只能精确到毫秒。
}
}
3.5.4.2LocalDate、LocalTime、LocalDateTime
LocalDate:代表本地日期(年、月、日、星期)
LocalTime:代表本地时间(时、分、秒、纳秒)
LocalDateTime:代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)
它们获取对象的方案
LocalDate的常用API (都是处理年、月、日、星期相关的)
什么是时区
- 由于世界各个国家与地区的经度不同,各地区的时间也有所不同,因此会划分为不同的时区。
Zoneld时区的常见方法
ZonedDateTime带时区时间的常见方法
示例:
Test1_LocalDate
package com.itheima.jdk8_time;
import java.time.LocalDate;
public class Test1_LocalDate {
public static void main(String[] args) {
//0、获取本地日期对象
LocalDate ld=LocalDate.now();//年月日
System.out.println(ld);
//1、获取日期对象中的信息
int year= ld.getYear();//
int month = ld.getMonthValue();//(1-12)
int day = ld.getDayOfMonth();//
int dayOfYear=ld.getDayOfYear();//一年中的第几天
int dayOfWeek=ld.getDayOfWeek().getValue();//星期几
System.out.println(year);
System.out.println(day);
System.out.println(dayOfWeek);
//2、直接修改某个信息:withYear、withMonth、withDayOfMonth、withDayIOfYear
LocalDate ld2=ld.withYear(2099);
LocalDate ld3=ld.withMonth(9);
System.out.println(ld);//2024-03-30,说明是不可变对象
System.out.println(ld2);//2099-03-30
System.out.println(ld3);//2024-09-30
//3、把某个信息加多少:plusYears、plusMonths、plusDays、plusWeeks
LocalDate ld4=ld.plusYears(2);
LocalDate ld5=ld.plusMonths(2);
//4、把某个信,息减多少:minusYears、minusMonths、minusDays、minusWeeks
LocalDate ld6=ld.minusYears(2);
LocalDate ld7=ld.minusMonths(2);
//5、获取指定日期的LocalDate对象:public static LocalDate of(int year,int month,int day)
LocalDate ld8=LocalDate.of(2077,7,7);
LocalDate ld9=LocalDate.of(2077,7,7);
//6、判断2个日期对象,是否相等,在前还是在后:equals isBefore isAfter
System.out.println(ld8.equals(ld9));//true
System.out.println(ld8.isAfter(ld));//true
System.out.println(ld8.isBefore(ld));//false
}
}
Test2_LocalTime
package com.itheima.jdk8_time;
import java.time.LocalTime;
public class Test2_LocalTime {
public static void main(String[] args) {
//0、获取本地时间对象
LocalTime lt=LocalTime.now();//时分秒纳秒不可变的
System.out.println(lt);
//1、获取时间中的信息
int hour = lt.getHour();//时
int minute = lt.getMinute();//分
int second = lt.getSecond();//秒
int nano=lt.getNano();//纳秒
//2、修改时间:withHour、withMinute、withSecond、withNano
LocalTime lt3 = lt.withHour(10);
LocalTime lt4 = lt.withMinute(10);
LocalTime lt5 = lt.withSecond(10);
LocalTime lt6 = lt.withNano(10);
//3、加多少:plUsHours、plusMinutes、plusSeconds、plusNanos
LocalTime lt7 = lt.plusHours(10);
LocalTime lt8 = lt.plusMinutes(10);
LocalTime lt9 = lt.plusSeconds(10);
LocalTime lt10 = lt.plusNanos(10);
//4、减多少:minusHours、minusMinutes、minusSeconds、minusNanos
LocalTime lt11 = lt.minusHours(10);
LocalTime lt12 = lt.minusMinutes(10);
LocalTime lt13 = lt.minusSeconds(10);
LocalTime lt14 = lt.minusNanos(10);
//5、获取指定时间的localTome对象:
//public static LocalTime of(int hour,int minute,int second)
LocalTime lt15 =LocalTime.of(12,12, 12);
LocalTime lt16 = LocalTime.of(12,12,12);
//6、判断2个时间对象,是否相等,在前还是在后:equals isBefore isAfter
System.out.println(lt15.equals(lt16));
System.out.println(lt15.isAfter(lt));
System.out.println(lt15.isBefore(lt));
}
}
Test3_LocalDateTime
package com.itheima.jdk8_time;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Test3_LocalDateTime {
public static void main(String[] args) {
//0、获取本地日期和时间对象。
LocalDateTime ldt= LocalDateTime.now();//年 月 日 时 分 秒 纳秒
System.out.println(ldt);
//1可以获取日期和时间的全部信息
int year = ldt.getYear();//年
int month = ldt.getMonthValue();//
int day = ldt.getDayOfMonth();//
int dayOfYear=ldt.getDayOfYear();//一年中的第几天
int dayofWeek=ldt.getDayOfWeek().getValue();//获取是周几
int hour = ldt.getHour();//
int minute = ldt.getMinute();//
int second = ldt.getSecond();//
int nano = ldt.getNano();//纳秒
//2、修改时间信息:
//withYear withMonth withDayofMonth withDayofYear withHour withMinute withSecond withNano
LocalDateTime ldt2=ldt.withYear(2029);
LocalDateTime ldt3 = ldt.withMinute(59);
//3、加多少:
//plusYears plusMonths plusDays plusWeeks plusHours plusMinutes plusSeconds plusNanos
LocalDateTime ldt4 = ldt.plusYears(2);
LocalDateTime ldt5 = ldt.plusMinutes(3);
//4、减多少:
//minusDays minusYears minusMonths minusWeeks minusHours minusMinutes minusSeconds minusNanos
LocalDateTime ldt6 =ldt.minusYears(2);
LocalDateTime ldt7 =ldt.minusMinutes(3);
//5、获取指定日期和时间的LocalDateTime对象:
//public static LocalDateTime of(int year,Monthmonth,int dayofMonth,int hour,
// int minute,int second,int nanoOfSecond)
LocalDateTime ldt8 = LocalDateTime.of(2028,12,5,9,30,10,1200);
LocalDateTime ldt9 = LocalDateTime.of(2029,12,5,9,30,10,1200);
//6、判断2个日期、时间对象,是否相等,在前还是在后:equals、isBefore、isAfter
System.out.println(ldt9.equals(ldt8));
System.out.println(ldt9.isAfter(ldt));
System.out.println(ldt9.isBefore(ldt));
//7、可以把LocalDateTime转换成LocalDate和ocalTime
//public LocalDate toLocalDate()
//public LocalTime toLocalTime()
//public static LocalDateTime of(LocalDatddde date,LocalTime time)
LocalDate ld=ldt.toLocalDate();
LocalTime lt=ldt.toLocalTime();
LocalDateTime ldt10=LocalDateTime.of(ld,lt);
}
}
Test4_ZoneId_ZonedDateTime
package com.itheima.jdk8_time;
import java.time.Clock;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.zip.ZipEntry;
public class Test4_ZoneId_ZonedDateTime {
public static void main(String[] args) {
//目标:了解时区和带时区的时间。
//1、ZoneId的常见方法:
//public static ZoneId systemDefault():获取系统默认的时区
ZoneId zoneId =ZoneId.systemDefault();
System.out.println(zoneId.getId());
System.out.println(zoneId);//实际上是调用toString方法
//public static Set<String>getAvailableZoneIds():获取Java支持的全部时区Id
System.out.println(ZoneId.getAvailableZoneIds());
//public static ZoneId of(String zoneId):把某个时区id封装成ZoneId对象。
ZoneId Id1=ZoneId.of("America/Cuiaba");
//2、ZonedDateTime:带时区的时间。
//public static ZonedDateTime now(ZoneId zone):获取某个时区的ZonedDateTime对象。
ZonedDateTime now = ZonedDateTime.now(Id1);
System.out.println(now);
//世界标准时间
ZonedDateTime now1 = ZonedDateTime.now(Clock.systemUTC());
System.out.println(now1);
//public static ZonedDateTime now():获取系统默认时区的ZonedDateTime对象
ZonedDateTime now2 = ZonedDateTime.now();
System.out.println(now2);
//Calender instance= Calendar.getInstance(TimeZone.getTimeZone(Id1));过时了
}
}
3.5.4.3 Instant
Instant时间线上的某个时刻/时间戳
- 通过获取1 nstant的对象可以拿到此刻的时间,该时间由两部分组成:从1970-01-0100:00:00开始走到此刻的总秒数+不够1秒的纳秒数
- 作用:可以用来记录代码的执行时间,或用于记录用户操作某个事件的时间点。
- 传统的Date类,只能精确到毫秒,并且是可变对象。
- 新增的Instant类,可以精确到纳秒,并且是不可变对象,推荐用Instant代替Date。
示例
Test5_Instant
package com.itheima.jdk8_time;
import java.time.Instant;/*
*目标:掌握Instont的使用。
*/
public class Test5_Instant{
public static void main(String[] args){
//1、创建Instant的对象,获取此刻时间信息
Instant now = Instant.now();//不可变对象
//获取总秒数
long second = now.getEpochSecond();
System.out.println(second);
//3、不够一秒的纳秒数
int nano =now.getNano();
System.out.println(nano);
System.out.println(now);
Instant instant = now.plusNanos(111);
//Instant对象的作用:代码性能分析,或记录用户的操作时间点
Instant now1 = Instant.now();
//代码执行...
Instant now2 = Instant.now();
}
}
3.5.4.4DateTimeFormatter
LocalDateTime提供的格式化、解析时间的方法
示例
Test6_DateTimerFormatter
package com.itheima.jdk8_time;
//目标:掌握JDK8新增的DateTimeFormatter格式化器的用法。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Test6_DateTimerFormatter {
public static void main(String[] args) {
//1.创建一个日期时间格式化器对象出来
DateTimeFormatter formatter =DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
//2.对时间进行格式化
LocalDateTime now=LocalDateTime.now();
System.out.println(now);
String rs=formatter.format(now);//正向格式化
System.out.println(rs);
//格式化时间,其实还有一种方法
String rs2=now.format(formatter);//反向格式化
System.out.println(rs2);
//4.解析时间,解析时间一般使用LocalDateTime提供的解析方法来解析。
String dateStr ="2029年12月12日 10:10:8";
LocalDateTime ldt =LocalDateTime.parse(dateStr,formatter);
System.out.println(ldt);
}
}
3.5.4.5Period与Duration
Period(一段时期)
- 可以用于计算两个LocalDate对象相差的年数、月数、天数。
Duration(持续时间) - 可以用于计算两个时间对象相差的天数、小时数、分数、秒数、纳秒数;支持LocalTime、LocalDateTime、Instant等时间
示例:
Test7_Period
package com.itheima.jdk8_time;
import java.time.LocalDate;
import java.time.Period;
//目标:掌握Period的作用:计算机两个日期相差的年数,月数、天数。
public class Test7_Period {
public static void main(String[] args) {
LocalDate start =LocalDate.of(2029,8,10);
LocalDate end =LocalDate.of(2035,10,15);
//1.创建Period对象,封装两个日期对象
Period period= Period.between(start,end);
//2.通过period对象获取两个对象相差的信息
System.out.println(period.getYears());//间隔6年
System.out.println(period.getMonths());//间隔2个月
System.out.println(period.getDays());//间隔5天
}
}
Test8_Duration
package com.itheima.jdk8_time;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
//目标:掌握Period的作用:计算机两个日期相差的年数,月数、天数。
public class Test8Duration {
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2025, 11, 11, 10, 10);
LocalDateTime end = LocalDateTime.of(2025, 11, 11, 11, 11);
//1、得到Duration对象
Duration duration = Duration.between(start,end);
//2.获取两个时间对象间隔的时间
System.out.println(duration.toDays());//间隔多少天
System.out.println(duration.toHours());//间隔多少小时
System.out.println(duration.toMinutes());//间隔多少分
System.out.println(duration.toSeconds());//间隔多少秒
System.out.println(duration.toMillis());//间隔多少毫秒
System.out.println(duration.toNanos());//间隔多少纳秒,秒都是累积起来的
}
}
3.5.5Arrays
Arrays
- 用来操作数组的一个工具类。
Arrays.类提供的的常见方法Arrays
如果数组中存储的是对象,如何排序?
- 方式一: 让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。
- 方式二:使用下面这个sort方法,创建Comparator比较器接口的匿名内部类对象,然后自己制定比较规则。
自定义排序规则时,需要遵循的官方约定如下:
示例:
Student
package com.itheima.arrays;
public class Student implements Comparable<Student>{
private String name;
private double height;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", height=" + height +
", age=" + age +
'}';
}
//指定比较规则
//this o
@Override
public int compareTo(Student o){
//约定1:左边对象大于右边对象,返回正整数
//约定2:左边对象小于右边对象,返回负整数
//约定3:左边对象等于于右边对象,返回0
//按照年龄升序。
/* if(this.age>o.age){
return 1;
}else if(this.age<o.age){
return -1;
}
return 0;
*/
//一行代码实现
//return this.age-o.age;//升序
return -(this.age-o.age);//降序
}
public Student() {
}
public Student(String name, double height, int age) {
this.name = name;
this.height = height;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Test1
package com.itheima.arrays;
import com.itheima.d6_enum.A;
import java.util.Arrays;
import java.util.function.IntToDoubleFunction;
public class Test1 {
public static void main(String[] args) {
//1、public static String toString(类型[] arr):返回数组的内容
int[] arr={10,20,40,60};//[10, 20, 40, 60]
System.out.println(Arrays.toString(arr));
//2、public static int[] copyOfRange(类型[] arr,起始索引,结束索引):拷贝数组(指定范围,包前不包后)
int arr2[]= Arrays.copyOfRange(arr,1,3);//[20, 40]
System.out.println(Arrays.toString(arr2));
//3、public static copyof(类型[] arr,int newLength.):拷贝数组,可以指定新数组的长度。
int arr3[] = Arrays.copyOf(arr,10);
System.out.println(Arrays.toString(arr3));//[10, 20, 40, 60, 0, 0, 0, 0, 0, 0]
int arr4[] = Arrays.copyOf(arr,3);
System.out.println(Arrays.toString(arr4));//[10, 20, 40]
//4、public static setAll(double[] array,IntToDoubleFunction generator):把数组中的原数据改为新数据又存进去。
double[] prices={99.8,128,100};
//所有价格打八折,然后存进去
Arrays.setAll(prices, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int value) {//会一个一个拿索引
return 0.8*prices[value];
}
});
System.out.println(Arrays.toString(prices));//此错没有失真,若失真,就要用BigDecimal处理
//5、public static void sort(类型[] arr):对数组进行排序(默认是升序排序)
Arrays.sort(prices);
System.out.println(Arrays.toString(prices));
}
}
Test2
package com.itheima.arrays;
import com.itheima.d6_enum.A;
import java.util.Arrays;
import java.util.Comparator;
public class Test2 {
public static void main(String[] args) {
//目标:掌握如何对数组中的对象进行排序
Student[] students =new Student[4];
students[0]=new Student("蜘蛛精",169.5,23);
students[1]=new Student("紫霞",165.8,25);
students[2]=new Student("至尊宝",178.5,29);
students[3]=new Student("牛魔王",185.4,28);
//1.public static void sort(类型[] arr);对数组进行排序
//2.public static <T> void sort(T[] arr, Comparator<? super T> c)
//参数一:需要排序的数组
//参数二:Comparator比较器对象(用来指定对象的比较规则)
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//指定比较规则
//约定1:左边对象大于右边对象,返回正整数
//约定2:左边对象小于右边对象,返回负整数
//约定3:左边对象等于于右边对象,返回0
/*按照身高升序,注意身高是double,不能直接做差,老老实实if语句
if(o1.getHeight()> o1.getHeight()){
return 1;
}else if(o1.getHeight()<o2.getHeight()){
return -1;
}
return 0;*/
//一行代码搞定
return Double.compare(o1.getHeight(),o2.getHeight());//升序
// return -Doublepare(o1.getHeight(),o2.getHeight());//降序
}
});
System.out.println(Arrays.toString(students));
}
}
3.5.6JDK8新特性:Lambda表达式
3.5.6.1认识Lambda表达式
Lambda表达式
- Lambda表达式是JDK8开始新增的一种语法形式;作用:用于简化匿名内部类的代码写法。
格式
什么是函数式接口?
- 有且仅有一个抽象方法的接口。
- 注意:将来我们见到的大部分函数式接口,上面都可能会有一个@Functionalinterface的注解,有该注解
的接口就必定是函数式接口。
3.5.6.2Lambda表达式的省略规则
Lambda表达式的省略写法(进一步简化Lambda表达式的写法)
- 参数类型可以省略不写。
- 如果只有一个参数,参数类型可以省略,同时()也可以省略。
- 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!此时,如
果这行代码是return语句,也必须去掉return不写。
示例:
Student
package com.itheima.arrays;
public class Student implements Comparable<Student>{
private String name;
private double height;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", height=" + height +
", age=" + age +
'}';
}
//指定比较规则
//this o
@Override
public int compareTo(Student o){
//约定1:左边对象大于右边对象,返回正整数
//约定2:左边对象小于右边对象,返回负整数
//约定3:左边对象等于于右边对象,返回0
//按照年龄升序。
/* if(this.age>o.age){
return 1;
}else if(this.age<o.age){
return -1;
}
return 0;
*/
//一行代码实现
//return this.age-o.age;//升序
return -(this.age-o.age);//降序
}
public Student() {
}
public Student(String name, double height, int age) {
this.name = name;
this.height = height;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Test1
package com.itheima.arrays;
import com.itheima.d6_enum.A;
import java.util.Arrays;
import java.util.function.IntToDoubleFunction;
public class Test1 {
public static void main(String[] args) {
//1、public static String toString(类型[] arr):返回数组的内容
int[] arr={10,20,40,60};//[10, 20, 40, 60]
System.out.println(Arrays.toString(arr));
//2、public static int[] copyOfRange(类型[] arr,起始索引,结束索引):拷贝数组(指定范围,包前不包后)
int arr2[]= Arrays.copyOfRange(arr,1,3);//[20, 40]
System.out.println(Arrays.toString(arr2));
//3、public static copyof(类型[] arr,int newLength.):拷贝数组,可以指定新数组的长度。
int arr3[] = Arrays.copyOf(arr,10);
System.out.println(Arrays.toString(arr3));//[10, 20, 40, 60, 0, 0, 0, 0, 0, 0]
int arr4[] = Arrays.copyOf(arr,3);
System.out.println(Arrays.toString(arr4));//[10, 20, 40]
//4、public static setAll(double[] array,IntToDoubleFunction generator):把数组中的原数据改为新数据又存进去。
double[] prices={99.8,128,100};
//所有价格打八折,然后存进去
Arrays.setAll(prices, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int value) {//会一个一个拿索引
return 0.8*prices[value];
}
});
System.out.println(Arrays.toString(prices));//此错没有失真,若失真,就要用BigDecimal处理
//5、public static void sort(类型[] arr):对数组进行排序(默认是升序排序)
Arrays.sort(prices);
System.out.println(Arrays.toString(prices));
}
}
Test2
package com.itheima.arrays;
import com.itheima.d6_enum.A;
import java.util.Arrays;
import java.util.Comparator;
public class Test2 {
public static void main(String[] args) {
//目标:掌握如何对数组中的对象进行排序
Student[] students =new Student[4];
students[0]=new Student("蜘蛛精",169.5,23);
students[1]=new Student("紫霞",165.8,25);
students[2]=new Student("至尊宝",178.5,29);
students[3]=new Student("牛魔王",185.4,28);
//1.public static void sort(类型[] arr);对数组进行排序
//2.public static <T> void sort(T[] arr, Comparator<? super T> c)
//参数一:需要排序的数组
//参数二:Comparator比较器对象(用来指定对象的比较规则)
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//指定比较规则
//约定1:左边对象大于右边对象,返回正整数
//约定2:左边对象小于右边对象,返回负整数
//约定3:左边对象等于于右边对象,返回0
/*按照身高升序,注意身高是double,不能直接做差,老老实实if语句
if(o1.getHeight()> o1.getHeight()){
return 1;
}else if(o1.getHeight()<o2.getHeight()){
return -1;
}
return 0;*/
//一行代码搞定
return Double.compare(o1.getHeight(),o2.getHeight());//升序
// return -Doublepare(o1.getHeight(),o2.getHeight());//降序
}
});
System.out.println(Arrays.toString(students));
}
}
3.5.7JDK8新特性:方法引用
静态方法的引用
- 类名::静态方法
使用场景
- 如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用.
实例方法的引用
- 对象名::实例方法.
使用场景
- 如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用.
特定类型的方法引用
- 类型::方法.
使用场景
- 如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用.
构造器引用
- 类名::new
使用场景
●如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用.
示例:
Car
package com.itheima.method_references;
public class Car {
private String name;
private double price;
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
public Car() {
}
public Car(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
CompareByData
package com.itheima.method_references;
import com.itheima.arrays.Student;
public class CompareByData {
public static int compareByAge(Student o1, Student o2){
return o1.getAge()- o2.getAge();//升序排序的规则;
}
public int compareByAgeDesc(Student o1,Student o2){
return o2.getAge()-o1.getAge();//降序排序的规则;
}
}
Test1
package com.itheima.method_references;
import com.itheima.arrays.Student;
import com.itheima.d6_enum.A;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
public class Test1 {
public static void main(String[] args) {
Student[] students =new Student[4];
students[0]=new Student("蜘蛛精",169.5,23);
students[1]=new Student("紫霞",165.8,25);
students[2]=new Student("至尊宝",178.5,29);
students[3]=new Student("牛魔王",185.4,28);
//原始写法:对数组中的学生对象,按照年龄升序排序
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()- o2.getAge();//按照年龄升序排序
}
});
//使用Lambda表达式进行简化
//Arrays.sort(students,((o1, o2) -> o1.getAge()- o2.getAge()));
//Arrays.sort(students,((o1, o2) -> CompareByDatapareByAge(o1,o2)));
//静态方法引用
// Arrays.sort(students, CompareByData::compareByAge);
Arrays.sort(students,((o1, o2) -> o2.getAge()- o1.getAge()));
CompareByData compare=new CompareByData();
Arrays.sort(students,((o1, o2) -> compare.compareByAgeDesc(o1,o2)));
//实例方法引用
Arrays.sort(students, compare::compareByAgeDesc);
System.out.println(Arrays.toString(students));
}
}
Test2
package com.itheima.method_references;
import java.util.Arrays;
import java.util.Comparator;
public class Test2 {
public static void main(String[] args) {
String[]names = {"boby","angela","Andy","dlei","caocao","Babo","jack","cici"};
//进行排序(默认字典序)
Arrays.sort(names);
//忽略带小写比较
/* Arrays.sort(names, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//制定比较规则。 o1="Andy" o2="angela"
return o1pareToIgnoreCase(o2);
}
});
*/
//简化
//Arrays.sort(names,( o1,o2) -> o1pareToIgnoreCase(o2));
//再次简化
Arrays.sort(names,String::compareToIgnoreCase);
System.out.println(Arrays.toString(names));
}
}
Test3
package com.itheima.method_references;
import com.itheima.d6_enum.A;
//目标:构造器引用(理解语法)
public class Test3 {
public static void main(String[] args) {
//1.创建这个接口的匿名内部类对象。
/* CreateCar cc=new CreateCar(){
@Override
public Car create(String name,double price){
return new Car(name,price);
}
};*/
// CreateCar cc=( ( name, price)->new Car(name,price));
//构造器引用
CreateCar cc=Car::new;
Car c = cc.create("奔驰", 49.9);
System.out.println(c);
}
}
interface CreateCar{
Car create(String name,double price);
}
版权声明:本文标题:【Java基础二】 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1727168653a1100043.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论