java学习笔记part3 day01,day02
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 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 {
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();
}
}
接口注意事项
-
接口不能创建对象
-
一个类可以实现多个接口,多个接口中有同样的静态方法不冲突(只能接口自己调用 接口.方法名)
-
一个类继承父类,同时实现接口,父类中和接口中有同名的方法,默认使用父类的
-
一个类实现多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可
-
一个接口继承多个接口,如果多个接口中规范冲突则不能继承