6.1 关键字 static
一、关键字的使用
1.static说明
1)静态的
2)static 可以用来修饰:
属性、方法、代码块、内部类
2.使用static修饰属性
(静态变量)(类变量)
3.1属性:按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过一个对象修改静态变量时,会导致其他对象调用此静态变量时使用的时修改过了的变量。
3.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载。(实例变量是随着对象的创建而加载)
②静态变量的加载要早于对象的创建
③由于类只会加载一次,则静态变量在内存中也只存在一份(存在方法区的静态域中)
3.3 静态属性举例: System.out Math.PI
package com.atguigu.java1; public class StaticTest { public static void main(String[] args) { Chinese.nation = "China"; Chinese c1 = new Chinese(); c1.name = "姚明"; c1.age = 40; c1.nation = "CHINA"; Chinese c2 = new Chinese(); c2.name = "马龙"; c2.age = 30; System.out.println(c2.nation); } } class Chinese{ String name; int age; static String nation; }
3.使用static修饰方法
(静态方法)
① 随着类的加载而加载,可以通过“类.静态方法”来进行调用
③静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态方法或属性,也可以调用静态的方法或属性
4.类变量 vs 实例变量的内存解析
5.static注意点:
1)在静态的方法内,不能使用static关键字,super关键字
2)关于静态属性和静态方法的使用,也可以从生命周期的角度理解
6.总结:
在开发中,如何确定一个属性是否要加static
>属性是可以被多个对象所共享的,不会随着对象的不同而不同的
在开发中,如何确定一个方法是否要加static
>操作静态属性的方法,通常设置为静态的
>工具类中的方法,习惯上声明为static:如Math、Arrays、Collections
7.练习
单例(Singleton)设计模式
23种设计模式:
实现方式:
1.饿汉式单例设计模式
package com.atguigu.java2; public class SingletonTest1 { public static void main(String[] args) { Bank bank1 = Bank.getInstance(); Bank bank2 = Bank.getInstance(); System.out.println(bank1 == bank2);//true } } //饿汉式单例设计模式 class Bank{ //1.私有化构造器 private Bank() { } //2.内部创建类的对象 //4.要求此对象也必须声明为静态的 private static Bank instance = new Bank(); //3.提供公共的静态的方法,返回类的对象 public static Bank getInstance() { return instance; } }
2.懒汉式单例设计模式
package com.atguigu.java2; public class SingletonTest2 { public static void main(String[] args) { Order order1 = Order.getInstance(); Order order2 = Order.getInstance(); System.out.println(order1 == order2); } } //饿汉式单例设计模式 class Order{ //1.私有化类的构造器 private Order() { } //2.声明当前类对象,没有初始化 //4.此对象也必须声明为static的 private static Order instance = null; //3.声明public static的返回当前类对象的方法 public static Order getInstance() { if(instance == null) { instance = new Order(); } return instance; } }
3.区分饿汉式和懒汉式
饿汉式:坏处 对象加载时间过长
好处 饿汉式是线程安全的
懒汉式:好处 延迟对象的创建
坏处 目前写法线程不安全。 --> 到多线程内容时再修改
4.单例模式的应用场景
6 - 2 理解main方法的语法
一、main 方法的使用说明
1.main方法作为程序的入口
2.main()方法也是一个普通的静态方法
3.main()方法也可以作为我们与控制台交互的一种方式
:先编译-->RUN AS-->RUN configuration --> arguement
*、理解
关于在main方法中调用本类的其他非static方法,必须先实例化本类对象,再在main方法中进行调用:
main方法是static方法,随着类的加载而生成。而非static方法在类加载时并未产生,只有实例化对象后才会产生非static方法,所以要想在main方法中调用非static方法,必须先实例化对象声称该方法,再对该方法进行调用。
main方法中调用static对象,可以直接调用。
非static方法中调用static/非static方法,可以直接调用。
6 - 3 类的成员之四:代码块
(或初始化块)
一、代码块的作用:
1.用来初始化类、对象
2.代码块如果有修饰的话,只能使用static
3.分类:
静态代码块 vs 非静态代码块
4.静态代码块
1)内部可以有输出语句
2)随着类的加载而执行,而且只执行一次。
3)初始化类的一些信息
4)如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
5)静态代码块执行要优先于非静态代码块的执行
5.非静态代码块
1)随着对象的创建而执行
2)每创建一个,就执行一次非静态代码块
3)作用:可以在创建对象时,对对象的属性等进行初始化
4)如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
5)静态代码块执行要优先于非静态代码块的执行
*.对属性可以赋值的位置:
①默认初始化
②显式初始化
③构造器中初始化
④有了对象以后,可以通过“对象.属性”或“对象.方法”的方式进行赋值
⑤在代码块中赋值
执行的先后顺序:1-2/5-3-4
总结:由父及子,静态先行
package com.atguigu.java3; public class Block { public static void main(String[] args) { String desc = Person.desc; Person p1 = new Person(); Person p2 = new Person(); } } class Person{ String name; int age; static String desc = "我是一个人"; public Person(){ } public Person(String name,int age) { this.name = name; this.age = age; } //static代码块 static { System.out.println("hello, static block - 1"); } static{ System.out.println("hello, static block - 2"); } //非static代码块 { System.out.println("hello, block"); } //方法: public void eat() { System.out.println("吃饭"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public static void info() { System.out.println("我是一个快乐的人"); } }
6 - 4 关键字:final
1.final可以用来修饰的结构
类、方法、变量
2.final修饰类
此类不能被其他类所继承
比如:String类,System类,StringBuffer
3.final 用来修饰方法
表明此方法不可以被重写
4.final用来修饰变量
此时的变量就称为是一个常量
1)final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
2)final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能重新进行赋值
static final:用来修饰属性:全局常量(相当于c语言中#define NUM = 10;)
6 - 5 抽象类与抽象方法
一.abstract关键字的使用
1.abstract:抽象的
2.abstract可以用来修饰的结构:类、方法
3.abstract修饰类:抽象类
1)此类不能实例化
2)抽象类中一定有构造器,便于子类对象实例化时候调用
3)开发中,都会提供抽象类的子类,让子类对象实例化,完成实际的操作
4.abstract修饰方法:抽象方法
1)抽象方法只有方法的声明,没有方法体
2)包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法
3)子类重写了父类中所有抽象方法后,子类方可实例化。
反之,子类也是一个抽象类,需要用abstract修饰。
*.理解:
抽象方法不能被调用,如果是普通的类,能产生对象,则就能通过对象.方法的形式对方法进行调用,故只有抽象类(不同产生实例化对象)可以包含抽象方法
二、abstract注意点
1.abstract不能用来修饰:属性、构造器等结构;(不能重写)
2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类
(abstract方法一定要在某个子类中被重写成普通方法,若改抽象方法私有,则不能被重写,编译不能通过)
(父类子类有同名同参数的static方法,不认为两个方法构成重写)登录 · 语雀
三、抽象类的匿名子类的使用
//创建了一个匿名类的对象:p Person p = new Person(){ @Override public void eat() { // TODO Auto-generated method stub } @Override public void breath() { // TODO Auto-generated method stub } }; //创建了一个匿名子类的匿名对象 method1(new Person(){ @Override public void eat() { System.out.println("吃好吃的东西"); } @Override public void breath() { System.out.println("好好呼吸"); } });
可以理解为创建了一个匿名子类的对象,对象名用抽象父类的名充当,故称为抽象类的匿名子类
四、模板方法设计模式
package com.atguigu.java; public class TemplateTest { public static void main(String[] args) { Template t = new SubTemplate(); t.spendTime(); } } abstract class Template{ //计算某段代码执行所需要花费的时间 public void spendTime(){ long start = System.currentTimeMillis(); this.code();//不确定的部分,易变的部分 long end = System.currentTimeMillis(); System.out.println("花费的时间为:" + (end - start)); } public abstract void code(); } class SubTemplate extends Template{ @Override public void code() { for(int i = 2;i <= 1000;i++) { boolean isFlag = true; for(int j = 2;j <= Math.sqrt(i);j++) { if(i % j == 0) { isFlag = false; break; } } if(isFlag) { System.out.println(i); } } } }
五、练习
练习二
package com.atguigu.exer1; public abstract class Employee { private String name; private int id; private double salary; public Employee(){ } public Employee(String name,int id,double salary){ this.name = name; this.id = id; this.salary = salary; } public abstract void work(); }
package com.atguigu.exer1; public class Manager extends Employee{ private int bonus; public Manager(){ super(); } public Manager(String name,int id,double salary,int bonus){ super(name,id,salary); this.bonus = bonus; } public void work(){ System.out.println("管理员工,提高了公司的运行效率"); } }
package com.atguigu.exer1; public class CommonEmployee extends Employee{ public void work(){ System.out.println("员工在一线车间生产产品"); } }
练习三
package com.atguigu.exer2; abstract public class Employee { private String name; private int number; private MyDate birthday; //构造器 public Employee(){ } public Employee(String name, int number, MyDate birthday) { super(); this.name = name; this.number = number; this.birthday = birthday; } //toString方法 @Override public String toString() { return "name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString() ; } //getter and setter public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public MyDate getBirthday() { return birthday; } public void setBirthday(MyDate birthday) { this.birthday = birthday; } //abstract method public abstract double earnings(); }
package com.atguigu.exer2; class MyDate{ private int year; private int month; private int day; //Constructure public MyDate(int year, int month, int day) { super(); this.year = year; this.month = month; this.day = day; } //toString方法 public String toDateString(){ return year + "年" + month + "月" + day + "日"; } //getter and setter public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } }
package com.atguigu.exer2; public class SalariedEmployee extends Employee { private double monthlySalary; public SalariedEmployee(String name, int number, MyDate birthday) { super(name, number, birthday); } public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) { super(name, number, birthday); this.monthlySalary = monthlySalary; } //override abstract method @Override public double earnings(){ return monthlySalary; } //override toString method @Override public String toString() { return "SalariedEmployee[" + super.toString() + "]"; } //getter and setter public double getMonthlySalary() { return monthlySalary; } public void setMonthlySalary(double monthlySalary) { this.monthlySalary = monthlySalary; } }
package com.atguigu.exer2; public class HourlyEmployee extends Employee{ private double wage;//时薪 private int hour;//月工作的小时数 public HourlyEmployee(String name, int number, MyDate birthday) { super(name, number, birthday); } public HourlyEmployee(String name, int number, MyDate birthday, double wage, int hour) { super(name, number, birthday); this.wage = wage; this.hour = hour; } @Override public double earnings(){ return wage * hour; } @Override public String toString() { return "HourlyEmpoyee[" + super.toString() + "]"; } //getter and setter public double getWage() { return wage; } public void setWage(double wage) { this.wage = wage; } public int getHour() { return hour; } public void setHour(int hour) { this.hour = hour; } }
package com.atguigu.exer2; import java.util.Calendar; import java.util.Scanner; public class PayrollSystem { public static void main(String[] args) { //方式一: /* Scanner scanner = new Scanner(System.in); System.out.println("请输入当月的月份:"); int month = scanner.nextInt();*/ //方式二: Calendar calendar = Calendar.getInstance(); int month = calendar.get(Calendar.MONTH) + 1;//获取当前的月份(1月份是0) Employee[] emps = new Employee[2]; emps[0] = new SalariedEmployee("Mbappe", 1002, new MyDate(1992, 2, 28), 18000); emps[1] = new HourlyEmployee("Dingye_Zhang", 1003, new MyDate(2003, 3, 24), 50, 400); for(int i = 0;i < emps.length;i++ ) { System.out.println(emps[i].toString()); double salary = emps[i].earnings(); System.out.println("月工资为" + salary); if(month == emps[i].getBirthday().getMonth()) { salary += 100; System.out.println(emps[i].getName() + "生日快乐,奖励100元"); } } } }
总结:
抽象类中包含着抽象的方法,意味着子类必须实现所有抽象方法才能够实例化。抽象类定义了子类所共有的特点,但是由于各子类特点之间差距较大,不能在父类中直接定义,所以干脆父类不提供共有的方法,只提供一个方法格式供子类实现,故引入了抽象类和抽象方法的概念
6 - 6 接口(interface)
一、接口的使用
1.接口使用interface来定义
2.Java中,接口和类是并列的两个结构
3.如何定义接口:
定义接口中的成员
3.1 JDK7及以前:
只能定义全局常量和抽象方法
>全局常量:public static final的,但是书写时可以省略不写
>抽象方法:public abstract的
3.2 JDK8:
除了定义全局变量和抽象方法之外,还可以定义静态方法、默认方法(略)
4.接口中不能定义构造器!
意味着接口不能够实例化
5.Java开发中,接口通过让类去实现(implements)的方式来使用
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
6.Java类可以实现多个接口
--> 弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD{
}
7.接口与接口之间可以继承,而且可以多继承
8.接口的具体使用,体现多态性
9.接口,实际上可以看作是一种规范
面试题:抽象类与接口有哪些异同?
二、接口的使用
1.接口使用上也满足多态性
2.接口实际上就是定义了一种规范
3.开发中,体会面向接口编程
三、接口的匿名实现类
我们传入驱动方法的永远是实现类的对象,此对象可以是匿名的。同时,由于实现类相当于抽象父类(接口)的子类,故实现类也可以是匿名的。
package com.atguigu.java1; public class USBTest { public static void main(String[] args) { Computer com = new Computer(); //1.创建了接口的非匿名实现类的非匿名对象 Flash flash = new Flash(); com.transferData(flash); //2.创建了接口的非匿名实现类的匿名对象 com.transferData(new Flash()); //3.创建了接口的匿名实现类的非匿名对象 USB phone = new USB(){ @Override public void start() { System.out.println("手机开始工作"); } @Override public void stop() { System.out.println("手机结束工作"); } }; com.transferData(phone); //4. 创建了接口的匿名实现类的匿名对象 com.transferData(new USB(){ @Override public void start() { System.out.println("开始工作"); } @Override public void stop() { System.out.println("结束工作"); } }); } } //接受类中有驱动方法(传接口类) class Computer{ //驱动方法 public void transferData(USB usb){ usb.start(); System.out.println("具体传输数据的细节"); usb.stop(); } } interface USB{ public abstract void start(); public abstract void stop(); } //实现类中实现接口中的抽象方法 class Flash implements USB{ @Override public void start() { System.out.println("U盘开始工作"); } @Override public void stop() { System.out.println("U盘结束工作"); } }
四、代理模式
package com.atguigu.java1; public class NetWorkTest { public static void main(String[] args) { Server server = new Server(); ProxyServer proxyServer = new ProxyServer(server); proxyServer.browse(); } } interface NetWork{ public abstract void browse(); } //被代理类 class Server implements NetWork{ @Override public void browse() { System.out.println("真实的服务器访问网络"); } } //代理类 class ProxyServer implements NetWork{ private NetWork work; public ProxyServer(NetWork work) { this.work = work; } public void check(){ System.out.println("联网之前的检查工作"); } @Override public void browse() { check(); work.browse(); } }
自我总结:
对需要代理的方法提供相应接口,让代理类和被代理类都实现该抽象方法,被代理类作为实现类,而代理类作为接受类,在代理类中创建构造器,初始化接口类型的实例对象,但是注意,接口类型无实例对象,所以传入的对象一定要为被代理类(即实现类的实例对象),然后接着在被代理类实现接口中的方法,方法中即要调用代理类的代理方法,又可以有被代理类的方法,就实现了既屏蔽了对真实角色的直接访问,又可以实现其他功能
网络解释:
使用静态代理时需要让目标对象和代理对象一起实现相同的接口或者继承相同的父类。这样做的目的就是为了通过调用代理对象中和目标对象相同的方法来实现调用目标对象的方法,从而达到代理的效果。
五、接口课后两道笔试题
编译不通过,因为x不明确
接口继承两个接口中的同名抽象方法:实现一次该方法即可(题目中正确)
但接口中只能定义抽象方法和全局常量,所以ball是个全局常量,不可以修改,所以Ball类中不能对ball对象进行修改,编译不通过
六、练习
package com.atguigu.exer3; public interface CompareObject { public abstract int compareTo(Object o); }
package com.atguigu.exer3; public class Circle { private Double radius; public Circle(){ super(); } public Circle(double radius){ this.radius = radius; } public Double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } }
package com.atguigu.exer3; public class CompareableCircle extends Circle implements CompareObject{ public CompareableCircle(double radius) { super(radius); } @Override public int compareTo(Object o) { if(this == o){ return 0; } if(o instanceof CompareableCircle){ CompareableCircle o1 = (CompareableCircle)o; //错误的 //return (int)(this.getRadius() - o1.getRadius()); //正确的 if(this.getRadius() > o1.getRadius()){ return 1; }else if(this.getRadius() < o1.getRadius()){ return -1; }else{ return 0; } }else{ throw new RuntimeException("传入的类型不匹配"); }//还可以用包装类Double来判断 } }
package com.atguigu.exer3; public class InterfaceTest { public static void main(String[] args) { CompareableCircle c1 = new CompareableCircle(4.0); CompareableCircle c2 = new CompareableCircle(5.2); compareValueMethod(c1,c2); } public static void compareValueMethod(CompareableCircle c1,CompareableCircle c2){ int compareValue = c1.compareTo(c2); if(compareValue > 0) { System.out.println("c1对象半径大"); }else if(compareValue < 0){ System.out.println("c2对象半径大"); }else{ System.out.println("c1,c2对象半径一样大"); } } }
七、Java8新特性:
JDK8以后 除了定义全局变量和抽象方法之外,还可以定义静态方法、默认方法
默认方法的关键字是default
1.接口中定义的静态方法,只能通过接口来调用
2.通过实现类的对象,可以调用接口中的默认方法
如果实现类重写了接口中的默认方法,调用时,仍然调用重写方法
3.如果实现类继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法
4.如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法
那么在实现类没有重写此方法的情况下,报错。 --> 接口冲突
这就需要我们必须在实现类中重写此方法
5.如何在实现类中调用父类和接口中的方法
class SubClass extends SuperClass implements CompareA,CompareB{ public void method2(){ System.out.println("SubClass:上海"); } public void method3(){ System.out.println("SubClass:深圳"); } public void myMethod(){ method3();//调用自己重写的方法 super.method3();//调用父类中声明的方法 //调用接口中的默认方法 CompareA.super.method3(); CompareB.super.method3(); } }
八、总结:
1.项目的具体需求是多变的,我们必须以不变应万变才能从容开发,“不变”就是“规范”。因此,我们开发项目往往都是面向接口编程!
2.通常情况下,我们在接收类中提供接受接口的驱动方法。创建接受类的实例对象,调用此对象的驱动方法。驱动方法的形参是接口类型的实例对象,我们通过多态性,将实现类的对象传入驱动方法的形参中,然后运行实现对象的实现方法,来达到实现接口方法的目的。
6 - 7 类的内部成员之五:内部类
一、
1.说明
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
2.内部类的分类
成员内部类 vs 局部内部类(方法内,代码块内,构造器内)
3.成员内部类
一方面,作为外部类的成员:
>调用外部类的结构
>可以用static修饰
>可以被四种权限修饰
另一方面,作为一个类:
>类内可以定义属性、方法、构造器等
>可以被final修饰,表示此类不能被继承
>可以被abstract修饰
4.关注如下的三个问题
4.1如何实例化成员内部类的对象
4.2如何去在成员内部类中区分调用外部类的结构
4.3开发中如何使用局部内部类 见<InnerClassTest.java>
package com.atguigu.java2; public class InnerClassTest { public static void main(String[] args) { //创建Dog实例(静态的成员内部类) Person.Dog dog = new Person.Dog(); dog.show(); //创建Bird实例(非静态的成员内部类) Person p1 = new Person(); Person.Bird bird = p1.new Bird(); bird.sing(); bird.display("dapeng"); } } class Person{ String name = "Mbappe"; int age; public void eat(){ System.out.println("人:吃饭"); } //静态成员内部类 static class Dog{ String name; int age; public void show(){ System.out.println("Dog:" + name); } } //非静态成员内部类 final class Bird{ String name = "kun"; public Bird(){ } public void sing(){ System.out.println("我是一只小小鸟"); Person.this.eat();//调用外部类的属性 } public void display(String name){ System.out.println(name);//方法的形参 System.out.println(this.name);//内部类的属性 System.out.println(Person.this.name);//外部类的属性 } } public void method(){ //局部内部类 class AA{ } } { //局部内部类 class BB{ } } public Person(){ //局部内部类 class CC{ } } }
package com.atguigu.java2; public class InnerClassTest1 { //开发中很少见 public void method(){ //局部内部类 class AA{ } } //返回一个实现了Comparable接口类的对象 public Comparable getComparable(){ //创建一个实现了Comparable接口的类 //方式一: /* class MyComparable implements Comparable{ @Override public int compareTo(Object o) { return 0; } } return new MyComparable();*/ //方式二: return new Comparable(){ @Override public int compareTo(Object o) { // TODO Auto-generated method stub return 0; } }; } }