面向对象高级
static关键字
static用来修饰的结构:属性、方法;代码块、内部类
我们可以按照变量在类中声明的位置,分为局部变量和成员变量。对于成员变量又可以进一步分类:
对于加了static关键字的变量,我们称为静态变量、类变量;
对于没有加static关键字的变量,我们称为实例变量、非静态变量。
静态变量和实例变量对比
|
静态变量 |
实例变量 |
个数 |
只有一份,被类的多个对象共享 |
每一个对象都保存有一份 |
内存位置 |
jdk6及之前,在方法区,jdk7及之后再堆 |
存放在堆空间的对象实体中 |
生命周期 |
随类的加载而加载,随类的卸载而消亡 |
随对象的创建而加载,随对象的消亡儿消亡 |
调用者 |
可被类直接调用,也可被对象调用 |
只能被对象调用 |
static修饰方法
-
随着类的加载而加载
-
可以通过“类.静态方法”的方式,直接调用静态方法
-
静态方法内可以调用静态的属性或静态的方法,不可以调用非静态的结构(比如属性和方法)
-
静态方法可被类直接调用,也可被对象调用;实例方法只能被对象调用
-
静态方法内不能用this和super(理解:因为静态方法随类的加载而加载,而this和super都是需要产生对象才可以使用的,但是VM是先加载类再加载对象,所以静态方法使用this和super显然是不合适的)
什么时候要使用static?
- 属性:1)当前类的对象是否能共享此属性,且此变量值相同。2)常量
- 方法:方法内操作的变量都是静态变量。工具类的方法,如:Arrays、Maths
单例(Singleton)设计模式
饿汉式
1 2 3 4 5 6 7 8 9 10 11
| class Bank{ private Bank(){ } private static Bank instace = new Bank(); public static Bank getInstance(){ return instance; } }
|
“立即加载”,随着类的加载就创建了
优点:写法简单,运行较快,是线程安全的
缺点:内存占用时间长
懒汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class GirlFriend{ private Bank(){ } private static Bank instace =null; public static Bank getInstance(){ if(instance == null){ instance=new Bank(); } return instance; } }
|
“延迟加载”,在需要的时候才创建对象
优点:节省内存
缺点:线程不安全
类的成员之四:代码块
代码块,也叫初始化块。是用来初始化类或对象的信息。按照是否加static修饰分为静态代码块和非静态代码块。静态代码块随着类的加载而执行,由于类的加载只会执行一次,所以静态代码块只会执行一次;非静态代码块随着对象的创建而执行,没创建一个实例,都会执行一次。静态代码块要先于非静态代码块执行。
作用:可以把不同构造器中相同的部分写在代码块中进行赋值;对静态变量进行赋值。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public class UserTest2 { public static void main(String[] args) { User2 user1 = new User2(); System.out.println(user1.getInfo()); System.out.println("===================================="); User2 user2 = new User2("KuoZ", "80841007"); System.out.println(user2.getInfo()); } } class User2{ private String userName; private String password; private long registrationTime; public User2() {
this.userName=""+System.currentTimeMillis(); this.password="123456"; }
public User2(String userName, String password) { this.userName = userName; this.password = password; } { System.out.println("新用户注册"); this.registrationTime = System.currentTimeMillis(); }
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 long getRegistrationTime() { return registrationTime; }
public String getInfo() { return "用户名:" + userName + ", 密码:" + password + ", 注册时间:" + registrationTime; } }
|
总结:属性赋值的位置及过程
final关键字
final可以修饰类、方法、变量
final修饰类时,则此类无法被继承
final修饰方法时,则此方法无法被重写
final修饰变量时,则表示常量,无法被更改
你就是我的final了!
abstract关键字
abstract关键字可以修饰类和方法
abstract修饰类:
- 此类称为抽象类
- 不能实例化
- 抽象类要包含构造器,因为子类对象实例化时会间接调用父类的构造器
- 抽象类中不一定要有抽象方法,而抽象方法所在的类必须是抽象类
abstract修饰方法:
- 此方法即为抽象方法
- 抽象方法只有方法的声明,没有方法体
- 抽象方法的功能是确定的,只是不知道其如何实现的
- 子类必须重写父类所有抽象方法之后才可实例化,否则必须声明为抽象类
abstract不能修饰的结构:属性、构造器、代码块
与abstact矛盾的关键字:
私有方法:因为私有方法不能被重写
静态方法:阻碍静态方法使用类调用
final方法:不能重写
final类:不能继承
接口(interface)
接口的使用:
接口的本质是一个契约、规范、标准,制定好后大家都要遵守。
接口内部结构:
可以声明:
属性:必须使用public static final修饰
方法:jdk8之前:声明抽象方法,修饰为public abstract
jdk8:声明了静态方法、默认方法
jdk9:声明私有方法
不可以声明构造器、代码块等
1 2 3 4 5 6
| public static final int MIN_SPEED = 0; public static final int MAX_SPEED = 7900; public abstract void fly(); }
|
接口和类的关系:实现关系
格式class A extends SuperA implements B,C{}
A是SuperA的子类,是B、C的实现类
类可以实现多个接口,这种多实现性一定程度上弥补了单继承的局限性。类必须将实现的接口中的所有抽象方法都重写才能实例化,否则必须声明为抽象类。
接口和接口之间是可以有继承关系的,而且是多继承
接口的多态性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| public class InterfaceTest { public static void main(String[] args) { Camera camera = new Camera(); Computer computer = new Computer(); computer.DataTransfer(camera);
computer.DataTransfer(new printer());
USB usb1 =new USB(){ @Override public void start() { System.out.println("usb1 start"); } @Override public void stop() { System.out.println("usb1 stop"); } }; computer.DataTransfer(usb1); computer.DataTransfer(new USB() { @Override public void start() { System.out.println("usb2 start"); }
@Override public void stop() { System.out.println("usb2 stop"); } }); } } interface USB{ void start(); void stop(); } class Computer implements USB{ @Override public void start() { System.out.println("computer start"); }
@Override public void stop() { System.out.println("computer stop"); } public void DataTransfer(USB usb){ usb.start(); System.out.println("Data Transfer"); usb.stop(); } } class Camera implements USB{
@Override public void start() { System.out.println("camera start"); }
@Override public void stop() { System.out.println("camera stop"); } } class printer implements USB{
@Override public void start() { System.out.println("printer start"); } @Override public void stop() { System.out.println("printer stop"); } }
|
区分抽象类和接口:相同:都可以声明抽象方法;都不能实例化。不同:抽象类一定要有构造器,接口没有;关系不同。(指继承、实现、多继承)
jdk8和jdk9中接口的新特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public class ComparaATest { public static void main(String[] args) { ComparaA.method1(); SubClass subClass = new SubClass(); subClass.method2(); subClass.method3(); subClass.method4(); System.out.println("-----------------"); subClass.method(); } } interface ComparaA { public static void method1() { System.out.println("ComparaA method1"); }
default void method2() { System.out.println("ComparaA method2"); } default void method3() { System.out.println("ComparaA method3"); } default void method4() { System.out.println("ComparaA method4"); } } interface ComparaB { default void method3() { System.out.println("ComparaB method3"); } } class SubClass extends SuperClass implements ComparaA, ComparaB { @Override public void method3() { System.out.println("SubClass method3"); } public void method(){ method3(); super.method4(); ComparaA.super.method3(); ComparaB.super.method3(); } } class SuperClass{ public void method4() { System.out.println("SuperClass method4"); } }
|
类的成员之五:内部类
内部类的分类:
成员内部类:声明在外部类的里面
又分为是否使用static修饰,静态的成员内部类,反之为非静态。
局部内部类:声明在构造器、方法、代码块内
又分为是否匿名
成员内部类的理解
- 从类的角度看
- 可以声明属性、方法、构造器、代码块、内部类等
- 可以声明父类、实现接口
- 可以使用final修饰
- 可使用abstract修饰
- 从外部类的成员的角度看
- 在内部可调用外部类的的结构
- 可以声明为private(与外部类不同,外部类只能用public、缺省)
- 可以使用static修饰
如何创建成员内部类的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class InClassTest { public static void main(String[] args) { Person.Dog dog = new Person.Dog(); dog.eat(); Person person = new Person(); Person.Bird bird = person.new Bird(); bird.eat(); }
} class Person{ String name="张三"; static class Dog{ public void eat(){ System.out.println("Dog eat"); } } class Bird { String name="鸮"; public void eat() { System.out.println("Bird eat"); } } }
|
如何在成员内部类中调用外部类的结构
1 2 3 4 5
| public void show(String name){ System.out.println(name); System.out.println(this.name); System.out.println(Person.this.name); }
|
局部内部类的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class InnerTest2 { public Comparable getInstace() { class MyComparable implements Comparable { @Override public int compareTo(Object o) { return 0; } } MyComparable myComparable = new MyComparable(); return myComparable;
} }
|
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class InnerTest3 { public static void main(String[] args) { new A(){ @Override public void Method() { System.out.println("hello"); } }.Method(); new B(){ @Override void Method() { System.out.println("hello2"); } }.Method(); new C(){ void Method(){ System.out.println("hello3"); } }.Method(); } } interface A{ void Method(); } abstract class B{ abstract void Method(); } class C{ void Method(){} }
|
综上,针对抽象类(父类)、接口,都可通过上述方式创建**匿名子类(实现类)**的匿名对象来实现方法。
枚举类
枚举类本质上也是类,不过这个类的对象是有限、确定的,用户不能随意创建。
枚举类声明格式
enum 枚举名{}
,在枚举类中,必须先声明多个对象,对象之间用“,”连接。枚举类的属性必须为private final
参考代码及常用方法测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class EnumTest { public static void main(String[] args) { System.out.println(Season.SPRING); System.out.println(Season.SPRING.name()); Season[] seasons = Season.values(); for (int i = 0; i < seasons.length; i++) { System.out.println(seasons[i]); } String objName = "SUMMER"; Season season = Season.valueOf(objName); System.out.println(season); String wrongObjName = "SUMMER1"; System.out.println(Season.SPRING.ordinal()); } } enum Season{ SPRING("春天", "温暖"), SUMMER("夏天", "炎热"), AUTUMN("秋天", "凉爽"), WINTER("冬天", "寒冷"); private final String seasonName; private final String seasonDesc; private Season(String seasonName,String seasonDesc){ this.seasonName=seasonName; this.seasonDesc=seasonDesc; } @Override public String toString() { return "Season{" + "seasonName='" + seasonName + '\'' + ", seasonDesc='" + seasonDesc + '\'' + '}'; } }
|
枚举实现接口的操作:
- 枚举类实现接口,在枚举类中重写接口的抽象方法。当通过不同的枚举类对象调用此方法时,执行同一个方法
- 枚举类每一个对象重写接口的抽象方法。当通过不同的枚举类对象调用此方法时,执行不同方法
针对2,要让枚举类的每一个对象重写接口的抽象方法,具体操作参考如下:
1 2 3 4 5 6
| SPRING("春天", "温暖"){ @Override public void show() { System.out.println("春天来了"); } },
|
注解
注解(annotation),与注释类似但并不相同,注解是可以被编译器读取的。
常见的Java内置注解:
@override
用于检查重写方法是否写对。
@Deprecated
表示某个类或方法已经不推荐使用,调用时会有警告提示。调用被它标记的类或方法时会出现删除线。
@SuppressWarnings
告诉编译器忽略特定类型的警告。
框架 = 注解 + 反射 + 设计模式
元注解:注解的注解
包装类
概述
使用包装类的原因:为了使基本数据类型具备引用数据类型变量的特征,给8中基本数据类型都提供了相应的包装类。
基本数据类型的包装类
对于8种数据类型,int、char的包装类为Integer、Character,byte、short、long、float、double、boolean为将首字母大写。
基本数据类型与引用数据类型的转换:
(装箱)基本数据类型–>包装类:1.使用包装类的构造器 2.(建议)使用包装类的valueOf()
(拆箱)包装类–>基本数据类型:调用包装类的xxxValue()
jdk5.0新特性:自动装箱和自动拆箱,直接赋值就能自动装/拆
String和基本数据类型、包装类的转换
基本数据类型、包装类–>String类型:1.调用String类重载的方法valueOf();2.使用基本数据类型/包装类+“”
String类型–>基本数据类型、包装类:调用包装类的静态方法:parseXxx()
IDEA快捷键
功能 |
快捷键 |
使用xx块环绕-surround with |
ctrl+alt+t |
复制指定行代码 |
ctrl+d |
删除指定行代码 |
ctrl+y |
切换到上一行代码空位 |
ctrl+alt+enter |
上下移动代码 |
ctrl+shift+↑/↓ |
上下移动代码 |
alt+shift+↑/↓ |
形参列表提醒 |
ctrl+p |
批量修改 |
shift+f6 |
重写父类的方法 |
ctrl+o |
实现接口的方法 |
ctrl+i |
查看源码 |
ctrl+click或者ctrl+n |
打开的类文件之间切换 |
ctrl+alt+←/→ |
切换标签 |
alt+←/→ |
查看继承树关系 |
ctrl+h |
类的UML关系图 |
ctrl+alt+u |
全项目搜索文本 |
ctrl+shift+f |
格式化代码 |
ctrl+alt+l |
哎,咱快累死了,不过终于是把这面向对象学完了。
说起来明天咱居然就要20岁了,感觉好突然呐Σ( ° △ °|||)︴
附一张赫萝表情包
