面向对象(高级)
类对象和类方法
static是所有对象共享的。静态域存储与定义类型的class对象的尾部,存放在堆中。在类加载的时候就生成了(不一定需要创建一个新的对象,没有创建对象时也可以使用),在类消亡时消亡
定义语法:
访问修饰符 static 数据类型 变量名;
如何访问类变量
类名.类变量名
或者对象名.类变量名【注意修饰符的访问权限】
类变量使用细节:
需要让某个类的所有对象共享一个变量,可以作出静态变量
类变量是所有对象共享,而属性也就是实例变量是每个对象独有的
加上static 称为静态变量,否则叫普通变量/非静态变量/成员变量(属性)都可以
类方法中不允许使用和对象相关的关键字,比如this和super关键字
类方法中只能访问静态属性和静态方法
普通成员两者都可以访问
main方法语法
public static void main(String[] args){
1.main方法是java虚拟机调用
2.java虚拟机需要调用,所以必须是public(不在同一个包)
3.在执行main()时不需要创建对象,子需要调用,所以用static
4.该方法接收string类型的数组参数 args,保存执行java命令中传入的参数
5.main方法可以调用当前类的静态方法和静态属性,但是不能调用非静态方法和非静态属性
代码块
//将构造器中相同的代码放入代码块,不管调用按俄国构造器,创建对象后,代码块都会先调用
代码块优先于方法构造器调用
#####注意事项:
静态代码块在类加载的时候执行,而且只执行一次,普通代码块只要创建对象就执行
只使用静态成员时,不调用普通代码块
一个类创建多个对象,只执行一次
类什么时候被加载
1、创建对象实例时,
2、创建子类对象实例时,父类对象也会被加载
3、使用类的静态方法或者静态属性时
#### 创建一个对象在类中的调用顺序
1、调用静态代码块和静态属性初始化(注意:静态代码块和静态属初始化优先级一样,多个的话按照定义的顺序执行)
2、调用普通代码块和普通属性初始化(注意:普通代码块和普通属初始化优先级一样,多个的话按照定义的顺序执行)
4、构造器的最前面隐含了super()和调用普通代码块,静态相关的在类加载时就已经执行完毕,因此优先于构造器和普通代码块。
单例设计模式
1、饿汉式
//单例模式-饿汉式:在不使用时对象就已经创建好了,容易造成创建了对象但是不使用
2、懒汉式
//单例模式-懒汉式:在使用getInstance时对象才创建
//1.将构造器私有化
//2.在类的内部创建对象,顶贴以一个静态属性变量
//3.提供给一个public方法,返回一个cat对象
final关键字
//如果不希望a类被继承,可以用final修饰
final class A{}
class C{
//如果要求c方法不能被子类重写和覆盖,可以使用final来修饰该方法
public final void c(){
}
}
class D extends C{
public void c(){//报错,无法重写
System.out.println("c类被重写");
}
}
//不希望类的某个属性的值被修改,可以使用final进行修饰
class E{
public final double x = 0.06;
}
class F{
public void f(){
//不希望类的某个局部变量的值被修改,可以使用final进行修饰
final double x = 0.7;
}
}
1.命名的字符全部大写:TAX_RATE
赋值位置
静态不能再构造器中赋值,因为类加载时static优先于构造器。
###抽象类
//即: 父类方法不确定性的问题
//=> 考虑将该方法设计为抽象(abstract)方法
//=> 所谓抽象方法就是没有实现的方法
//=> 所谓没有实现就是指,没有方法体
//=> 当一个类中存在抽象方法时,需要将该类声明为 abstract 类
//===> 一般来说,抽象类会被继承,有其子类来实现抽象方法.
注意事项
//抽象类不能被实例化
//抽象类不一定要包含抽象方法,可以有,也可以没有,
//还可以有实现的方法
//类如果包含抽象方法,那这个类就必须定义成抽象类
//抽象abstract只能修饰类和方法
//抽象类还是类,可以有任何成员,方法,构造器,属性等
//抽象方法不能有主体
//如果一个类继承了抽象类,必须实现抽象类的所有方法,除非它也是一个抽象类
//抽象方法不能用final、private、static来修饰,因为他们斗鱼重写相关
接口
普通类实现接口,必须实现接口中的所有方法,快捷键:alt + enter (普通类实现接口,必须使用public)
接口和继承额关系(接口比继承更加灵活)
接口的多态
public static void main(String[] args) {
//创建手机,相机对象
Camara camara = new Camara();
Phone phone = new Phone();
//创建计算机
Computer computer = new Computer();
computer.work(camara);//把相机接入了计算机
//把phone类型向上转成usb类型,类似于继承的向上转型
computer.work(phone)
}
多态数组
public class InterArr {
public static void main(String[] args) {
//接口的多态数组
Usb[] usbs= new Usb[2];
usbs[0] = new Phone_();
usbs[1] = new Camara_();
for(int i=0;i<usbs.length;i++){
usbs[i].work();//动态绑定,向下转型
if(usbs[i] instanceof Phone_){
Phone_ phone = (Phone_)usbs[i];
phone.call();
}
}
}
}
interface Usb{
void work();
}
class Phone_ implements Usb{
public void call(){
System.out.println("手机正在通话中");
}
@Override
public void work() {
System.out.println("手机工作中");
}
}
class Camara_ implements Usb{
@Override
public void work() {
System.out.println("相机工作中");
}
}
多态传递
public class InterfacePolyPass {
public static void main(String[] args) {
IG ig = new Teacher();//接口类型变量可以指向实现了该接口的类的对象实例
IH ih = new Teacher();//如果IG继承了IH接口,而teache类实现了IG接口,那么这个类也等于实现了IH接口
}
}
interface IH{}
interface IG extends IH{}
class Teacher implements IG{}
内部类(难点,重点)
/**
* 演示局部内部类的使用,一般定义在方法中
*/
public class Innerclass01 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.m1();
}
}
class Outer{//外部类
private int n1=100;
public void m1(){//方法
//局部内部类还是一个局部变量,所以不可以使用访问修饰符,但是可以使用final修饰符
//仅仅在定义它的方法或者代码块中使用
//局部内部类可以直接访问外部类的成员,比如m1和n2
//外部其他类不能访问局部内部类,因为它是一个局部变量
//如果外部类和局部内部类重名,遵循就近原则,如果像访问外部类的成员,可以使用外部类名.this.成员去访问
class Inner02{//局部内部类,可以访问外部类的所有成员
private int n1 = 800;
public void h1(){
//就近原则,输出800
System.out.println("n1 = "+ n1);
//可以使用外部类名.this.成员去访问值为100的n1,Outer.this指的就是这个对象
System.out.println("外部类n1 = "+ Outer.this.n1);
m1();
}
}
//外部类在方法中可以创建Inner02对象,然后调用即可
Inner02 inner02 = new Inner02();
inner02.h1();
}
{
//代码块
}
}
匿名内部类
本质:(1)本质是类(2)内部类(3)不需要定义类名(系统给你定义名字)(4)同时还是一个对象
匿名内部类还是一个局部变量
/**
* 演示匿名内部类的使用
*/
public class AnonymousInnerclass {
public static void main(String[] args) {
}
}
class Outer02{//外部类
private int n1 = 10;
public void method(){
//基于接口的匿名内部类
//1.想使用接口A,并创建对象
//2.传统方式,写一个类实现该接口,并创建对象
//3.但是A接口只使用一次,可以使用匿名内部类来简化开发
//tiger编译类型是A,运行类型是匿名内部类,不需要定义名字
// 系统定义名字为外部类名字$1,使用一次后就不能在使用
A tiger = new A(){
@Override
public void cry() {
System.out.println("小狗汪汪叫。。。");
}
};
tiger.cry();
//基于类的匿名内部类
//1.father编译类型Father ,运行类型Outer02$2
Father father = new Father("jack"){
};
father.test();
//基于抽象类的匿名内部类
M m = new M(){
@Override
void m1() {
}
};
m.m1();
}
}
interface A{//接口
public void cry();
}
class Father{//类
public Father(String name){
super();
}
public void test(){
}
}
abstract class M{
abstract void m1();
}
匿名内部类注意事项:
枚举类
自定义枚举类
public class Enumclass01 {
public static void main(String[] args) {
//对于季节而言,是由固定值的,只有四个,不会有更多,这样无法体现季节是有限的
//===>枚举类enumeration(把具体的对象一个个列举出来的类)
System.out.println(Season.autumn);
}
}
//演示自定义枚举的实现
//1、构造器私有化,防止 new
//2、去掉set方法,防止后续对属性进行修改
//3、在Season内部,直接创建固定的对象
//4、优化加final修饰符
//5\枚举对象名通常使用全部大写,常量命名规范。final修饰的变量基本全部大写。
class Season{
private String name;
private String desc;
//定义了四个对象
public final static Season spring = new Season("春天","温暖");
public final static Season winter = new Season("冬天","寒冷");
public final static Season summer = new Season("夏天","炎热");
public final static Season autumn = new Season("秋天","凉爽");
public Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
}
enum关键字
public class Enumeration {
public static void main(String[] args) {
System.out.println(Season2.SPRING);
}
}
//演示使用enum关键字来实现枚举类
//1、使用enum关键字代替class
//2、使用SPRING("春天","温暖");代替public final static Season2 spring = new Season2("春天","温暖");
//3、如果有多个对象直接用,隔开即可
//4、常量名(属性)写在枚举类的行首
enum Season2{
SPRING("春天","温暖"),WINTER("冬天","寒冷");
private String name;
private String desc;
//定义了四个对象
/*public final static Season2 spring = new Season2("春天","温暖");
public final static Season2 winter = new Season2("冬天","寒冷");
public final static Season2 summer = new Season2("夏天","炎热");
public final static Season2 autumn = new Season2("秋天","凉爽");*/
Season2(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season2{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
注意事项
实例
enum源码中有一个name属性,在创建Gender2对象时会把BOY赋值给name,由于子类没有toString方法,默认会调用父类的toString方法
Enum常用方法汇总(enum继承Enum后可用)
使用enum后自动继承Enum,不允许继承其他类;他和其他类一样,可以继承接口
注解的理解(annotation)
加注释override之后编译器会再次检测是否成功override,如果没有,则编译不通过,
@interface是注解的注解
元注解有四种
1、
2、
3、
4、
章节作业
public class Homework1 {
public static void main(String[] args) {
Car c = new Car();
Car c1 = new Car(100);
System.out.println(c);//9,red
System.out.println(c1);//100,red
}
}
class Car{
double price = 10;
static String color = "white";//静态变量类可以直接调用,只加载一次,创建第一个对象时,final关键字修饰之后是不可继承,不可修改
@Override
public String toString() {
return "price=" + price +"\t" + "color=" + color;
}
public Car() {
this.price = 9;
this.color = "red";
}
public Car(double price) {
this.price = price;
}
}
public class Homework2 {
public static void main(String[] args) {
Frock frock = new Frock();
System.out.println(frock.getSerialNumber());
Frock frock1 = new Frock();
System.out.println(frock1.getSerialNumber());
Frock frock2 = new Frock();
System.out.println(frock2.getSerialNumber());
}
}
class Frock{
private static int currentNum = 100000;
private int serialNumber;
public Frock() {
this.serialNumber = getNextNum();
}
public static int getNextNum(){
currentNum +=100;
return currentNum;
}
public int getSerialNumber() {
return serialNumber;
}
}
基于接口实现匿名内部类
public class Homework3 {
public static void main(String[] args) {
Animal cat = new Cat();
cat.shout();
Animal dog = new Dog();
dog.shout();
}
}
abstract class Animal{
abstract void shout();
}
class Cat extends Animal{
@Override
public void shout() {
System.out.println(“猫会喵喵叫”);
}
}
class Dog extends Animal{
@Override
void shout() {
System.out.println(“狗会汪汪叫”);
}
}
public class Homework4 {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
cellphone.testWork(new Computer() {
@Override
public double work(double A, double B) {
return A+B;
}
},10,8);
}
}
interface Computer{
public double work(double A,double B);
}
class Cellphone {
public void testWork(Computer computer,double A,double B){
double result = computer.work(A,B);
System.out.println(result);
}
}
局部内部类使用
public class Homework5 {
public static void main(String[] args) {
A a = new A();
a.Show();
}
}
class A{
private String name = "jack";
public void Show(){
class B{
private String name ="mary";
public void show(){
System.out.println("B中的name=" + name);
System.out.println("A中的name = " + A.this.name);
}
}
B b = new B();
b.show();
}
}
public class Homework6 {
public static void main(String[] args) {
Person tang = new Person("唐僧",new Horse());
}
}
interface Vehicles{
public void work();
}
class Horse implements Vehicles{
public void work(){
System.out.println("使用Horse作为交通工具");
}
}
class Boat implements Vehicles{
public void work(){
System.out.println("使用Boat作为交通工具");
}
}
class Factory {//设为静态,比较方便,不用创建对象
public static Horse getHorse(){
return new Horse();
}
public static Boat getBoat(){
return new Boat();
}
}
class Person{
private String name;
private Vehicles vehicles;
//在创建person对象时,一开始就分配了一个交通工具
public Person(String name, Vehicles vehicles) {
this.name = name;
this.vehicles = vehicles;
}
public void passRiver(){
//从工厂得到船
if(!(vehicles instanceof Boat)){//判断当前的vehiciel是不是空或者非船
vehicles = Factory.getBoat();
}
vehicles.work();
}
public void common(){
if(!(vehicles instanceof Horse)) {
vehicles = Factory.getHorse();
}
vehicles.work();
}
}