java学习笔记part3 day01,day02,day03
day01
static关键字
静态成员变量
-
可以修饰成员变量和成员方法,所属于类
-
static修饰成员变量,表示该成员变量只在内存中存储一份,可以被共享,修改
-
访问格式:类名.静态成员变量
实例成员变量
-
没有static修饰,存在于每个对象中,所属于对象
-
访问格式:对象.实例成员变量
package d1_static;
public class User {
/**
* static修饰的变量,静态成员变量,内存中只有一份,所属于类
*/
public static int onlineNumber = 161;
/**
* 实例成员变量,无static修饰,所属于对象,用对象名访问
*/
private String name;
private int age;
public static void main(String[] args) {
//1. 类名.静态成员变量,推荐方式
System.out.println(User.onlineNumber);
//2.对象名.实例成员变量,推荐方式
User u = new User();
u.name = "张三";
u.age = 21;
System.out.println(u.age);
System.out.println(u.name);
u.onlineNumber++;//使用对象名访问,不推荐
System.out.println(u.onlineNumber);
}
}
静态成员方法
- static修饰,归属于类,建议用类名访问,也可以用对象访问
实例成员方法
- 没有static修饰,只能用对象访问
package d1_static;
public class Student {
/**
* 实例成员变量,无static修饰,属于对象
*/
private String name;
/**
* 静态成员方法,有static修饰,,属于类。可以被共享访问,类名和对象名都可以访问
*/
public static int getMax(int age1, int age2){
return age1 > age2 ? age1 : age2;
}
/**
* 实例方法,属于对象,只能用对象访问
*/
public void study(){
System.out.println(name);
}
public static void main(String[] args) {
//1.类名.静态方法
System.out.println(Student.getMax(4, 6));
System.out.println(getMax(8, 6));//同一个类中,静态方法可以不写类名
//对象.实例方法
Student s = new Student();
s.name = "666";
s.study();
//对象.静态方法,(语法可行,不推荐)
System.out.println(s.getMax(3, 34));
}
}
使用场景
-
表示对象自己的行为的,方法中需要访问实例成员的,则该方法必须申明实例方法
-
如果该方法是以执行一个公用功能为目的,则可以申明成静态方法
注意事项
-
静态方式只能访问静态的成员,不可以直接访问实例成员
-
实例方法可以访问静态成员,也可以访问实例成员
-
静态方法中不可以出现this关键字,this关键字代表当前对象
工具类
- 类中都是一些静态的方法,每个方法都是以完成一个共用的功能为目的,这个类用来给系统开发人员使用
- 提高代码重用性
- 工具类里都是静态方法,直接访问类名就可调用,因此工具类无需创建对象,将工具类的构造器私有
package d2_static_util;
public class Login {
public static void main(String[] args) {
System.out.println(Util.createVerifyCode(5));
}
}
package d2_static_util;
public class Check {
public static void main(String[] args) {
System.out.println(Util.createVerifyCode(9));
}
} return code;
}
}
package d2_static_util;
import java.util.Random;
public class Util {
/**
* 工具类无需创建对象,将构造器私有化
*/
private Util() {
}
/**
* 静态方法
*/
public static String createVerifyCode(int n){
//开发验证码
//1.定义变量,保存验证码
String code = "";
//2.定义变量,记住全部验证码字符
String data = "qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNMM1234567890";
//3. 定义循环生成随机
Random r= new Random();
for (int i = 0; i < n; i++) {
//获取随机索引对应字符,连接给code
int index= r.nextInt(data.length());
code += data.charAt(index);
}
return code;
}
} return code;
}
}
练习
package d2_static_util;
public class Test2 {
public static void main(String[] args) {
int[] arr = {};
int[] arr1 = null;
int[] arr2 = {12, 23, 34};
System.out.println(ArrayUity.toString(arr));
System.out.println(ArrayUity.toString(arr1));
System.out.println(ArrayUity.toString(arr2));
}
}
package d2_static_util;
public class ArrayUity {
/**
* 私有构造器
*/
private ArrayUity() {
}
/**
* 工具方法静态方法
*/
public static String toString(int[] arr){
//1.校验
if(arr == null){
return null;
}
//2.拼接内容,返回
//result存储
String result = "[";
for (int i = 0; i < arr.length; i++) {
result += (i == arr.length -1 ?arr[i] : arr[i] + ",");
}
result += "]";
return result;
}
}
代码块
-
类的五大成分(成员变量,构造器,方法,代码块,内部类),定义在类中方法外
-
java类下,使用{}括起来的就是代码块
- 静态代码块:通过static关键字修饰,随着类的加载而加载,自动触发,只执行一次
public class StaticDemo1 {
public static String schoolName;
/**
* 静态代码块,有static修饰,属于类,与类一起优先加载,自动触发执行
* 可以用于初始化,静态资源
*/
static {
System.out.println("------------------------");
schoolName = "66学校";
}
public static void main(String[] args) {
//静态代码块
System.out.println(schoolName);
}
}
- 构造代码块:每次创建对象的时候,调用构造器执行,都会执行该代码块中的代码,并且在构造器执行前执行
package d3_static_code;
public class StaticDemo2 {
public String name;
public StaticDemo2(){
System.out.println("无参构造器被触发执行了");
}
/*
构造代码块,实例代码块,属于对象,调用构造器时先执行,没有static修饰
初始化实例资源
*/
{
name = "张三"
System.out.println("=========实例代码块========");
}
public static void main(String[] args) {
StaticDemo2 s1 = new StaticDemo2();
StaticDemo2 s2 = new StaticDemo2();
}
}
- 静态代码块应用案例
package d3_static_code;
import d2_static_util.ArrayUity;
import java.util.ArrayList;
public class StaticDemo3 {
/**
* 定义静态集合,这样静态集合只加载一个,只需要一幅牌
* static修饰,表示只在内存中存储一份,可以被共享,修改
*/
public static ArrayList<String> cards = new ArrayList<>();
/*
在程序main方法运行前,把54牌放进去,后续直接使用
*/
static {
//静态代码块,随着类的加载而加载,自动触发,执行一次
//定义数组存储点数
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//定义数组存储花色
String[] colors = {"♥","♠","♦","♣"};
//先遍历点数
for (int i = 0; i < sizes.length; i++) {
//sizes[i]
//遍历花色
for (int j = 0; j < colors.length; j++) {
//colors[j]
String card = colors[j] + sizes[i];
cards.add(card);
}
}
//大小王
cards.add("小");
cards.add("大");
}
public static void main(String[] args) {
System.out.println("新牌" + cards);
}
}
单例设计模式
-
设计模式,问题的最优解法,有20多种
-
单例模式,保证系统中,应用该模式的类永远只有一个实例,一个类只能创建一个对象
饿汉单例设计模式
-
用类获取对象的时候,对象已经提前创建好了
-
定义一个类,构造器私有
-
定义静态变量,存储一个对象
-
public class SingleInstance {
//2.饿汉单例在获取对象前,对象已经提前准备好
//对象只能是一个,所以定义静态成员变量
public static SingleInstance instance = new SingleInstance();
//1. 私有构造器
private SingleInstance() {
}
}
public class Test {
public static void main(String[] args) {
SingleInstance s1 = SingleInstance.instance;
SingleInstance s2 = SingleInstance.instance;
System.out.println(s1 == s2);
}
}
懒汉单例设计模式
-
真正需要对象时,才去创建一个对象(延迟加载对象)
-
构造器私有(单例)
-
静态变量存储对象
-
提供方法返回单例对象
-
package d4_sttatic_danli;
//懒汉单例的思想
public class SinglrInstance2 {
//2。定义静态成员变量存储单例对象,只加载一次
//私有化
private static SinglrInstance2 instance2;
//3.提供方法返回单例对象
public static SinglrInstance2 getInstance(){
if(instance2 == null){
//第一次,需要创建对象
instance2 =new SinglrInstance2();
}
return instance2;
}
//1. 构造器私有
private SinglrInstance2(){
}
}
package d4_sttatic_danli;
public class Test2 {
public static void main(String[] args) {
SinglrInstance2 sq = SinglrInstance2.getInstance();
SinglrInstance2 sq1 = SinglrInstance2.getInstance();
System.out.println(sq == sq1);
}
}
继承
-
提高代码复用性
-
java中关键字extends,使用这个关键字,可以让一个类和另一个类建立起父子关系
-
字类继承父类后,可以直接使用父类的属性和方法,字类更强大
package d5_extends;
//作为父类
public class People {
public void run(){
System.out.println("人会跑");
}
}
package d5_extends;
// 学生类,字类
public class Student extends People {
}
package d5_extends;
public class Test {
public static void main(String[] args) {
//继承
Student s = new Student();
s.run();
}
}
继承设计规范
-
字类们相同特征(共性属性,共性方法)放在父类中定义,
-
字类独有的属性,方法,行为应该定义在字类自己里面
package d6;
public class People { //父类
private String name;
private int age;
//方法,查看课表
public void qc(){
System.out.println(name + "在查看课表");
}
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;
}
}
package d6;
public class Student extends People { //继承
//字类独有行为
public void wi(){
System.out.println(getName() + "写作业了");
}
}
package d6;
public class Test {
public static void main(String[] args) {
//基础的设计思想
Student s = new Student();
s.setName("张三");//使用父类
s.setAge(23);//使用父类
System.out.println(s.getAge());//使用父类
System.out.println(s.getName());//使用父类
s.qc();//使用父类
s.wi();//使用字类
}
}
内存运行原理
继承的特定
-
字类可以继承父类的属性和行为,但是不能继承父类的构造器
-
java是单继承模式,一个类只能继承一个直接父类
-
java不支持多继承,但支持多层继承
-
Java中所有类都是Object类的字类
继承09,14
继承后成员变量,成员方法的访问特点
-
就近原则
-
局部没有找字类,字类没有找父类,父类没有报错
-
字类和父类出现重名成员,要使用父类的成员加super关键字
package d8;
public class Test {
public static void main(String[] args) {
//继承后,成员的访问特定
//就近原则
Dog d = new Dog();
d.lookDoor();//调用字类
d.run();//调用子类的
d.showName();
}
}
class Animal {
public String name = "动物名";
public void run(){
System.out.println("动物可以跑");
}
}
class Dog extends Animal{
public String name = "狗名";
public void lookDoor(){
System.out.println("狗看门");
}
public void run(){
System.out.println("狗跑的很快");
}
public void showName(){
String name = "局部名";
System.out.println(name);
System.out.println(this.name);//当前对象name,this代表当前对象的地址
System.out.println(super.name);//字类和父类重名时,要使用父类的成员,加关键字super
}
}
继承后方法重写
-
在继承关系中,字类和父类出现了一模一样的方法声明,我们就称字类这个方法是重写的方法
-
当字类需要父类的功能,但是父类的功能不能满足自己的需求时,字类就可以重写父类中的方法
-
方法重写的注意事项和要求,
one extend
重写校验注解,加上之后,方法必须是正确重写,提高程序的可读性-
重新方法的名称,形参列表必须和被重写方法的名称和参数保持一致
-
私有方法不能被重写
-
字类重写父类方法时,访问权限大于或等于父类
-
字类不能重写父类的静态方法,重写会报错
-
package dd9;
public class Test {
public static void main(String[] args) {
NewPhone p = new NewPhone();
p.call();
p.semndMag();
}
}
//父类
class Phone{
public void call(){
System.out.println("打电话");
}
public void semndMag(){
System.out.println("发短信");
}
}
//字类
class NewPhone extends Phone{
@Override //重写校验注解,加上之后,方法必须是正确重写,提高程序的可读性
public void call(){
super.call();
System.out.println("视频通话");
}
@Override
public void semndMag(){
super.semndMag();
System.out.println("发送图片");
}
}
继承后字类构造器的特点
-
字类中所有的构造器都会默认访问父类中的无参构造器,再执行自己
-
字类再初始化的时候,有可能会使用到父类中的数据,如果父类没有初始化,字类讲无法使用父类的数据
-
字类初始化前,一定要调用父类构造器完成父类数据空间的初始化
package d10;
public class Test {
public static void main(String[] args) {
//继承后字类构造器特定
Dog d = new Dog();
System.out.println(d);
Dog d2 = new Dog("hhh");
System.out.println(d2);
}
}
package d10;
public class Animal {
public Animal(){
System.out.println("父类无参构造器执行");
}
}
package d10;
import jdk.swing.interop.SwingInterOpUtils;
public class Dog extends Animal{
public Dog(){
System.out.println("字类无参构造器");
}
public Dog(String name){
System.out.println("字类有参构造器");
}
}
继承后,字类构造器访问父类的有参构造器
- super调用有参数构造器的作用,初始化继承自父类的数据
package d11;
public class Test {
public static void main(String[] args) {
//字类构造器访问父类有参构造器
Teacher t = new Teacher("dilei", 55);
System.out.println(t.getAge());
System.out.println(t.getName());
}
}
package d11;
public class People {
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
public People() {
}
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;
}
}
package d11;
public class Teacher extends People{
public Teacher (String name, int age){
//调用父类有参构造器,初始化继承自父类的数据
super(name, age);
}
}
this和super
-
this代表本类对象的引用
-
super,代表父类存储空间
-
this和super都要在构造器的第一行,儿二者不能在同一个构造器中
package d12;
public class Test {
public static void main(String[] args) {
//理解this
Student s1 = new Student("好家伙", "666");
System.out.println(s1.getName());
System.out.println(s1.getSchoolName());
Student s2 = new Student("shabi");
System.out.println(s2.getName());
System.out.println(s2.getSchoolName());
}
}
package d12;
public class Student {
private String name;
private String schoolName;
public Student() {
}
public Student(String name){
//借用本类兄弟构造器
this(name, "黑马");
}
public Student(String name, String schoolName) {
this.name = name;
this.schoolName = schoolName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
}
day02
包
-
用来管理不同的类,类似于文件夹
-
导包:相同包下的类可以直接使用,不同包下的类必须导包才能使用
package d1_package;
//导包
import d1_package.d1_package2.Student;
public class Test {
public static void main(String[] args) {
//1.同一个包下的可以直接访问
System.out.println(User.onlineNumber);
//2.不同包下的类,必须先导包才可以访问
Student s =new Student();
//3.如果这个类中使用不同包下的相同类名,默认只能导入一个类的包,另一个类的包,要使用全名访问
d1_package.d1_packer3.Student s2 = new d1_package.d1_packer3.Student();
}
}
权限修饰符
-
控制修饰的成员能够被访问的范围
-
可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受限制
-
有四种作用由小到大
- private,只能在当前类中访问
- 缺省,能在同一个类,同一个包中的其他类访问
- protected,同一个类中,同一个包中的其他类,不同包下的字类(使用字类创建新对象)
- public,同一个类中,同一个包中的其他类,不同包下的字类,不同包下的无关类
-
自定义成员满足以下要求:
- 成员变量一般私有
- 方法一般公开
- 如果该成员只希望本类访问,使用private
- 如果该成员只希望本类,同一个包下的其他类和字类访问,使用protected
final关键字
- 最终的意思,可以修饰类,方法,变量
- 修饰类:表明该类试最终类,不能被继承
- 修饰方法:表示该方法试最终方法,不能被重写
- 修饰变量:表明该变量最后一次赋值,不能被再次赋值(有且只能赋值一次)
public class Test {
public static void main(String[] args) {
//final语法
//final修饰类,类不能被继承,工具类可能使用
//final修饰方法,不能被重写
//final修饰变量,变量有且仅能被赋值一次
}
}
/*class Student extends People{
@Override
public void eat(){
System.out.println("学生也要吃");
}
}*/
class People{
public final void eat(){
System.out.println("人要吃饭");
}
}
/*
class wolf extends Animal
final class Animal{}*/
public class Test2 {
//final修饰的静态成员变量,常量
public static final String schoolName = "heima";
//实例成员变量,几乎不用
private final String name = "3333";
public static void main(String[] args) {
//final修饰变量的作用
//局部变量和成员变量,
//局部变量
final double score = 3.14;
// score = 3.3;第二次赋值
// schoolName = "dddd"第二次赋值
nam
}
}
-
注意:
-
final修饰的变量是基本类型,那么变量存储的数据值不能发生改变
-
final修饰的变量是引用类型,那么变量可存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的
-
public class Test1 {
public static void main(String[] args) {
//final修饰引用类型的变量,地址值不能发生改变,但是指向的内容可以改变
final Teachers t = new Teachers("学习");
System.out.println(t.getHobby());
t.setHobby("66666666666");
System.out.println(t.getHobby());
}
}
class Teachers{
private String hobby;
public Teachers(String hobby) {
this.hobby = hobby;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
常量
- 就是使用了public static final修饰的成员变量,必须有初始化值,指向过程中值不能被改变
- 作用和好处:可以用作系统的配置信息,方便维护,提高可读性
- 命名规范:英文单词全部大写,多个单词下划线连接起来
public class d1 {
public static final String SCHOOL_NAME = "44444";
public static void main(String[] args) {
// 常量的使用
System.out.println(SCHOOL_NAME);
}
}
-
常量的执行原理
- 在编译阶段会执行"宏替换",把使用常量的地方全部替换成真实的字面量
常量做信息标志和分类
- 代码可读性好,实现软编码形式
枚举类
-
java中特殊类型
-
做信息的标志和信息的分类
public enum Season {
//枚举第一行,罗列枚举类的对象名称,建议全队大写
SPRING, SUMMER, AUTUMN, WINTER;
}
javac进行编译
javap进行反编译
Compiled from "Season.java"
public final class Season extends java.lang.Enum<Season> {
public static final Season SPRING;
public static final Season SUMMER;
public static final Season AUTUMN;
public static final Season WINTER;
public static Season[] values();
public static Season valueOf(java.lang.String);
static {};
}
- 枚举的特点
- 枚举都是继承了枚举类型,java.lang.Enum
- 枚举都是最终类,不可以被继承
- 枚举类的构造器是私有的,枚举对外不能创建对象
- 枚举类的第一行默认都是罗列枚举对象的名称
- 枚举类,相当于多例模式
抽象类
- 在java中abstract是抽象的意思,可以修饰类,成员方法
//抽象类和抽象方法,都有sbstract修饰
public abstract class Animal {
//抽象方法不能写,方法体代码
public abstract void run();
}
//抽象方法只有方法签名,不能申明方法体
//一个类中如果定义了抽象方法,必须声明这个类成抽象类。
-
使用场景:一般作为父类,让字类继承
-
当父类知道字类要完成某些行为,但是每个字类该行为的实现方法不同,父类就把该行为定义成抽象方法的形式,具体实现交给字类去完成,此时这个类就可以声明成抽象类
抽象类的案例
public abstract class Card {
private String name;
private double money;
//定义支付方法,抽象方法
public abstract void pay(double money);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
public class GoldCard extends Card{
@Override
public void pay(double money2) {
System.out.println("当前消费" + money2);
System.out.println("当前余额" + getMoney());
double rs = money2 * 0.8;
System.out.println(getName() + "实际支付" + rs);
//跟新余额
setMoney(getMoney() - rs);
}
}
public class Test {
public static void main(String[] args) {
//抽象类的基本使用,做父类被继承,在重写抽象方法
GoldCard g = new GoldCard();
g.setMoney(10000);
g.setName("dilei");
g.pay(300);
System.out.println("剩余" + g.getMoney());
}
}
抽象类的特征,注意事项
-
类有的成分,抽象类都有
-
抽象类中不一定又抽象方法,有抽象方法一定是抽象类
-
类继承了抽象类,必须重写完抽象类的全部抽象方法,否则这个类定义成抽象类
-
不能用abstract修饰变量,代码块,构造器
-
抽象类不能创建对象
-
abstract和final互斥
模板方法模式
-
把功能定义成一个模板方法,放在抽象类中,模板方法中只定义通用且能确定的代码
-
模板方法把不能确实的功能,定义成抽象方法让字类实现
-
模板方法用final修饰,不能让字类重写
接口
-
interface关键字,接口也是一种规范
-
jdk8之前的接口只能写常量和抽象方法
//声明了接口
public interface InterfaceDemo {
//成分特点,jdk8之前接口中只能有抽象方法和常量
//常量
//由于接口体现规范思想,规范默认公开,代码层面,public abstract final可以省略
String SCHOOL_NAME1 = "黑马";
public static final String SCHOOL_NAME = "黑马";
//抽象方法
//由于接口体现规范思想,规范默认公开,代码层面,public abstract可以省略
void ruu();
public abstract void run();
}
接口的基本使用
-
接口是用来被类实现(implements)的,实际接口的类称为实现类,实现类可以理解成所谓的字类
-
implements,接口可以被类多实现,必须重写完接口的全部抽象方法
public interface SpotrMan {
void run();//接口
void bisai();
});
}
public interface law {
void rule();
}
public class pingpang implements SpotrMan, law {
private String name;
public pingpang(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name + "跑步");
}
@Override
public void bisai() {
System.out.println(name + "参加比赛");
}
@Override
public void rule() {
System.out.println(name + "守法");
}
}
public class Test {
public static void main(String[] args) {
//接口的基本使用,被类实现
pingpang p = new pingpang("张继科");
p.run();
p.bisai(); q
p.rule();
}
}
接口和接口的关系:多继承
- 一个接口可以继承多个接口
- 接口继承的作用:整合多个接口为同一个接口,便于字类实现
public interface laww {
void rulee();
}
public interface People {
void eat();
void sleep();
}
public interface SportM extends laww,People {
void run();
void bisai();
}
public class BasketBallMan implements SportM{
@Override
public void eat() {
}
@Override
public void sleep() {
}
@Override
public void run() {
}
@Override
public void bisai() {
}
@Override
public void rulee() {
}
}
public class Test {
public static void main(String[] args) {
//理解接口多继承
}
}
jdk8开始新增方法
package d13_interface_jdk8;
public interface SportMa {
/**
* jdk8新增默认方法,(实例方法)
* 必须default修饰,默认是public修饰
* 默认方法吊用,接口不能创建对象,过继给实现类,实现类的对象吊用
*/
default void run(){
System.out.println("paodekaui");
go();
};
/**
*静态方法
* 使用static修饰,默认public修饰
* 接口的静态方法,接口名自己吊用
*/
public static void inAdd(){
System.out.println("学习java新增方法");
}
/**
* jdk9新增方法,私有方法(实例方法)
* 必须在接口内部访问
*/
private void go(){
System.out.println("开始跑");
}
}
class PingPan implements SportMa{
}
class Test{
public static void main(String[] args) {
PingPan p = new PingPan();
p.run();
SportMa.inAdd();
}
}
接口注意事项
-
接口不能创建对象
-
一个类可以实现多个接口,多个接口中有同样的静态方法不冲突(只能接口自己调用 接口.方法名)
-
一个类继承父类,同时实现接口,父类中和接口中有同名的方法,默认使用父类的
-
一个类实现多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可
-
一个接口继承多个接口,如果多个接口中规范冲突则不能继承
day 03
多态
-
同类型的对象,执行同一个行为,会表现出不同的行为特征
-
多态的前提:有继承/实现关系;有父类引用指向字类对象;有方法重写
-
**多态的常见形式
父类类型 对象名称 = new 字类构造器
接口 对象名称 = new 实现类构造器
public class Test {
public static void main(String[] args) {
//1.多态的形式 父类类型 对象名称 = new 字类构造器
Animal a = new Dog();
a.run();//编译看左边,运行看右边
System.out.println(a.name);//编译看左,运行也看左(多态看重行为)
Animal a2 = new Tortoise();
a2.run();
System.out.println(a2.name);
}
}
多态中成员访问特点
-
方法调用:编译看左边,运行看右边
-
变量调用:编译看左边,运行也看左边
多态的优势
-
在多态形式下,右边对象可以实现解耦合,便于扩展个和维护
-
定义方法的时候:使用父类作为参数,该方法就可接收一切字类对象,体现出多态的扩展性和便利
问题
- 多态下不能使用字类的独有功能(编译看左边)
多态下引用数据类型的类中转换
-
强制类型转换:子类 对象变量 = (字类)父类类型的变量
-
作用:可以解决多态的劣势,可以实现调用字类独有的功能
-
强转转换之前,使用instanceof判断当前对象的真实类型,再进行强制转换
变量名 instanceof 真实类型
判断关键字左边的变量指向对象的真实类型,是否是右边的类型或者是其字类类型,是则返回true,反之false
public class Test {
public static void main(String[] args) {
//自动类型转换
Animal a = new Dog();
a.run();
//强制类型转换
Animal a2 = new Tortoise();
a2.run();
if(a2 instanceof Tortoise){
Tortoise t = (Tortoise) a2;
t.lay();
}else if(a2 instanceof Dog){
Dog d = new Dog();
d.look();
}
}
}
案例
package d4;
public class Computer {
private String name;
public Computer(String name) {
this.name = name;
}
public void start(){
System.out.println(name + "开机了");
}
//提供安装usb设备的入口
public void installUsb(Usb usb){
//多态,父类接口作为参数,所有行为对象都能进来\
usb.connect();
//独有功能,先判断再强转
if(usb instanceof KeyBoard){
KeyBoard k = (KeyBoard) usb;
k.keyDown();
}else if(usb instanceof Mouse){
Mouse m = (Mouse) usb;
m.dbClick();
}
usb.unconnect();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package d4;
public class KeyBoard implements Usb{//实现类
private String name;
public KeyBoard(String name) {
this.name = name;
}
@Override
public void connect() {
System.out.println("连接电脑");
}
//独有功能
public void keyDown(){
System.out.println("键盘敲击");
}
@Override
public void unconnect() {
System.out.println("拔出");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package d4;
public class Mouse implements Usb{
private String name;
public Mouse(String name) {
this.name = name;
}
@Override
public void connect() {
System.out.println("连接电脑");
}
//独有功能
public void dbClick(){
System.out.println("点击鼠标");
}
@Override
public void unconnect() {
System.out.println("拔出");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package d4;
public class Test {
public static void main(String[] args) {
//创建电脑对象
Computer c= new Computer("外星人");
c.start();
//创建鼠标,键盘对象
Usb k = new KeyBoard("双飞燕");
c.installUsb(k);
Usb m = new Mouse("逻辑");
c.installUsb(m);
}
}
package d4;
/**
* usb接口==规范
*/
public interface Usb {
//接入和拔出
void connect();
void unconnect();
}
内部类
-
定义在一个类里面的类,里面的类可以理解成寄生,外部类可以理解成宿主
-
使用场景:事物的内部,还有一部分需要一个完整的结构进行描述,而这个内部的完整结构又只为外部事物提供服务,那么内部的完整结构可以选择内部类来设计
-
内部类通常可以方便访问外部类的成员,包括私有成员
-
内部类提供更好的封装性,内部类本身就可以用prviate protectecd等修饰,封装性可以做更多控制
静态内部类
-
有static修饰,属于外部类本身
-
特点和使用与普通类一样,类有的成分都有,只是位置在别人里面
-
可以直接访问外部类的静态成员,不能直接访问外部类的实例成员
-
实际使用较少
package d5;
//外部类
public class Outer {
public static int a =10;
//静态成员内部类
public static class Inner{
private String name;
private int age;
public static String school_name;
public void show(){
System.out.println(name);
System.out.println(a);
}
public Inner(String name, int age) {
this.name = name;
this.age = age;
}
public Inner() {
}
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 static String getSchool_name() {
return school_name;
}
public static void setSchool_name(String school_name) {
Inner.school_name = school_name;
}
}
}
public class Test {
public static void main(String[] args) {
//外部类名.内部类 对象名 = new 外部类名.内部类
Outer.Inner i = new Outer.Inner();
i.setName("sha");
i.show();
}
}
成员内部类
-
无static修饰,属于外部类对象
-
jdk16之前,成员内部类中不能定义静态成员,jdk16开始可以定义静态成员
package d6;
//外部类
public class Outer {
//成员内部类
public class Iner {
private int age;
private String name;
public static int a = 100;//jdk16开始支持静态成员
public void show(){
System.out.println(name);
}
public static void test(){
System.out.println(a);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
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) {
Iner.a = a;
}
}
}
package d6;
public class Test {
public static void main(String[] args) {
//外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器
Outer.Iner in = new Outer().new Iner();
in.setName("sha");
Outer.Iner.test();//静态属于类
in.show();//实例属于对象
}
}
- 成员内部类中,访问外部类对象
package d6;
public class Test2 {
public static void main(String[] args) {
People.he heart = new People().new he();
heart.show();
}
}
class People{
private int heartbeat = 150;
public class he{
private int heartbeat = 110;
public void show(){
int heartbeat = 78;
System.out.println(heartbeat);//78
System.out.println(this.heartbeat);//110,实例成员变量属于对象,用this调用当前对象
System.out.println(People.this.heartbeat);//150,
}
}
}
局部内部类 -没啥大用
匿名内部类
-
没有名字的局部内部类,定义在方法,代码块中等
-
方便创建字类对象,简化编写
-
匿名内部类是一个没有名字的内部类
-
匿名内部类写出来就会产生一个匿名内部类的对象
package d7;
public class Test {
public static void main(String[] args) {
Animal a = new Animal(){
@Override
public void run() {
System.out.println("老虎跑的快");
}
};
a.run();
}
}
/*class Tiger extends Animal{
@Override
public void run() {
System.out.println("老虎跑的快");
}
}*/
abstract class Animal{
public abstract void run();
}
匿名内部类使用形式
- 可以作为方法的参数传输
package d8;
import org.w3c.dom.ls.LSOutput;
public class Test {
public static void main(String[] args) {
//匿名内部类使用形式
go(new Swimming() {//重写接口的方法,匿名内部类的对象
@Override
public void swim() {
System.out.println("学生游泳");
}
});
System.out.println("-----------------");
Swimming s2 = new Swimming() {//重写接口的方法,匿名内部类的对象
@Override
public void swim() {
System.out.println("老师游泳");
}
};
go(s2);
}
//学生,老师,运动员,参加游泳比赛
public static void go(Swimming s){
System.out.println("游");
s.swim();
}
}
/*class Student implements Swimming{
@Override
public void swim() {
System.out.println("学生游泳");
}
}*/
interface Swimming{
void swim();
}
常用API
- 应用程序编程接口,java写好的方法,直接使用
Object-toString
-
一个类中默认继承了Object类,要么简洁继承Object类,是java中的祖宗类
-
Object类的方法是一切字类都可以直接使用的
-
public String toString()--默认返回当对象在堆内存中的地址信息,类的全限名@内存地址,
-
让字类重写,以便返回字类对象的内容
package d9;
public class Student {
private String name;
private char sex;
private int age;
public Student() {
}
public Student(String name, char sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
'}';
}
}
package d9;
//Object类
public class Test {
public static void main(String[] args) {
Student s = new Student("zhang", '男' , 19);
// String rs = s.toString();
// System.out.println(rs);
//直接输出对象变量,toString默认可以省略不写
System.out.println(s.toString());
System.out.println(s);
}
}
Object-equals
package d9;
import java.util.Objects;
public class Student {
private String name;
private char sex;
private int age;
public Student() {
}
public Student(String name, char sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重写toString,返回对象内容
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
'}';
}
//重写equals,自己动议规则
// @Override
// public boolean equals(Object o){
// Student s2 = (Student) o;//o是Object,里面没有name,强制转换成Student类
// //判断o是不是学生类型
// if(o instanceof Student){
// //判断两个对象内容
//// if(this.name.equals(s2.name) && this.age == s2.age
//// && this.sex == s2.sex){
//// return true;
//// }else {
//// return false;
//// }
// return this.name.equals(s2.name) && this.age == s2.age
// && this.sex == s2.sex;
//
// }else {
// return false;
// }
// }
@Override
public boolean equals(Object o) {
if (this == o) return true;//判断是否是同一对象
if (o == null || getClass() != o.getClass()) return false;//null返回false,getClass()获取的类型不是o的类型,返回false
Student student = (Student) o; //类中转换
return sex == student.sex && age == student.age && Objects.equals(name, student.name);
}
}
package d9;
//equals
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student("zhang",'男',90);
Student s2 = new Student("zhang",'男',90);
//默认比较两个对象地址,==也可以
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
}
}
Objects-equals
-
Objects类和Object还是继承关系,Objects类是从jdk1,7开始才有的
-
Objects的eauals方法比较结果一样,更安全
package d10;
import java.util.Objects;
//Objects -equals
public class Test {
public static void main(String[] args) {
String s1 = null;
String s2 = "s";
//System.out.println(s1.equals(s2));//可能出现空值异常
System.out.println(Objects.equals(s1, s2));
}
}
Objects-isnull
- 判断是否为null
System.out.println(Objects.isNull(s1));
StringBuilder
- StringBuilder,是一个可变的字符串类,可以看作一个对象容器
- 作用:提高字符串的操作效率,如拼接,修改
package d11;
//StringBuilder,使用,原理
public class Test {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append(22);
sb.append(false);
System.out.println(sb);
StringBuilder sb1 = new StringBuilder();
//链式编程
sb1.append("a").append("c").append("c");
System.out.println(sb1);
//反转
sb1.reverse().append(110);
System.out.println(sb1);
System.out.println(sb1.length());
//StringBUilde,只是拼接字符串的手段,效率好
//最终的目的要恢复成String
//恢复成String
String sr = sb1.toString();
System.out.println(sr);
}
}
案例
package d11;
public class Test2 {
public static void main(String[] args) {
int[] arr1 = null;
System.out.println(toS(arr1));
int[] arr2 = {11,22,33};
System.out.println(toS(arr2));
}
//1,定义方法接收整型数组
public static String toS(int[] arr){
//拼接内容
if(arr != null){
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", ");
}
sb.append("]");
return sb.toString();
}else {
return null;
}
}
}
Math-工具类
-
包含执行基本数字运算的方法,Math类没有提供公开的构造器
-
都是静态类,通过类名直接调用
package d12;
public class test {
public static void main(String[] args) {
//1.取绝对值,返回正数
System.out.println(Math.abs(10));//10
System.out.println(Math.abs(-10.8));//10.8
//2.向上取整
System.out.println(Math.ceil(4.00000000000002));//5
//3.向下取整
System.out.println(Math.floor(4.999999999991));//4
//4.求指数次方
System.out.println(Math.pow(2, 3));//2^3=8
//5.四舍五入
System.out.println(Math.round(4.49));
System.out.println(Math.round(4.51));
//6.取随机数
System.out.println(Math.random());//0.0-1.0(包前不包后)
//3-9直接的随机数(减加法)
//0-1 * 6 + 3
int d = (int)(Math.random() * 7) + 3;
System.out.println(d);
}
}
system
- 功能是通用的,不能创建对象,静态方法
package d13;
import java.util.ArrayList;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
System.out.println("开始");
//1. System.exit(0);//jvm,0,正常终止
//计算机时间起源,返回1970-1-1 00.00.00
//2.算是c语言的生日
// long time = System.currentTimeMillis();
// System.out.println(time);
// //进行时间的计算
// long startTime = System.currentTimeMillis();
// for (int i = 0; i < 100000; i++) {
// System.out.println("输出" + i);
// }
// long endTime = System.currentTimeMillis();
// System.out.println((endTime - startTime)/1000.0 + "s");
/*arraycopy(Object src参数1, int srcPos拷贝开始位置,
Object dest复制到, int destPos粘贴位置,
int length拷贝个数);*/
//数组拷贝
int[] arr = {1,2,3,4,5,6,7,8};
int[] arr2 = new int[6];
System.arraycopy(arr, 3, arr2, 2, 3);
System.out.println(Arrays.toString(arr2));
System.out.println("结束");
}
}
BigDecimal
- 解决浮点型运算精度失真的问题
package d14;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Test {
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;
double c = a + b;
System.out.println(c);
//包装浮点型数据成为大数据对象 BigDeciaml
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);
double rs = c1.doubleValue();
System.out.println(rs);
//注意:BigDecimal,一定要精度运算
BigDecimal a11 = BigDecimal.valueOf(10.0);
BigDecimal b11 = BigDecimal.valueOf(3.0);
/*
* 参数1是除数
* 参数2保留小数位
* 参数3舍人
* */
BigDecimal c11 = a11.divide(b11, 2, RoundingMode.HALF_UP);
System.out.println(c11);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人