Static关键字:
static关键字的使用:
-
static:静态的
-
static可以用来修饰:属性、方法、代码块、内部类
-
使用static修饰属性:
3.1 属性,按是否使用sattic修饰,又分为:静态属性 vs 非静态变量(实例变量) 实例变量:创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性 当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改 静态变量:创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时, 会导致其他对象调用此静态变量时, 3.2 static修饰属性的其他说明: ① 静态变量随着类的加载而加载。可以通过“类.静态变量”的方式进行调用 ② 静态变量的加载要早于对象的创建 ③ 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中 ④ 类 实例变量 类 yes no 对象 yes yes 3.3 静态属性举例:System.out ; Math.PI;
-
使用static修饰方法:
①随着类的加载而加载,可以通过“类.静态方法”的方法进行调用 ② 类 实例变量 类 yes no 对象 yes yes ③ 静态方法中,只能调用静态的方法或属性 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
-
static注意点: 5.1 在静态的方法内,不能使用this关键字、super关键字 5.2 关于静态属性和静态方法的使用,都从生命周期的角度去理解
-
开发中,如何确定一个属性是否要声明为static的?
- 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
- 类中的常量也常常声明为static
开发中,如恶化确定一个方法是否要声明为static的?
- 操作静态属性的方法,通常设置为static的
- 工具类中的方法,习惯上声明为static的.比如:Math.PI、Arrays
代码块:
类的成员之四:代码块 (类的成员前三:属性、方法、构造器(构造方法))
- 代码块的作用:用来初始化类、对象
- 代码块如果有修饰的话,只能用static
- 分类:静态代码块 vs 非静态代码块
- 静态代码块:
- 内部可以有输出语句
- 随着类的加载而执行(自动执行),并且只执行一次
- 作用:初始化类的信息
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行(推荐合成一个,没有必要造多个代码块)
- 静态代码块的执行要优先于非静态代码块的执行
- 静态代码块内只能调用静态的属性、静态的方法、不能调用非静态的结构
- 非静态代码块:
- 内部可以有输出语句
- 随着类的创建而执行(自动执行)
- 每创建一个对象,就执行一次非静态代码块
- 作用:可以在创建对象时,对对象的属性等进行初始化
- 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行(推荐合成一个,没有必要造多个代码块)
- 非静态代码块内可以调用静态的属性、静态的方法、或非静态的属性、方法
对属性可以赋值的位置:
① 默认初始化
② 显式初始化
③ 构造器初始化
④ 有对象之后,可以以通过“对象.属性”或“对象.方法”的方式进行赋值
⑤ 在代码块中赋值
执行顺序:① -> ② \ ⑤ -> ③ -> ④(②与⑤,看写的位置)
public class Test012 {
public static void main(String[] args) {
String describle = Person.describle;
Person person = new Person();
}
}
class Person{
//属性
String name;
int age;
static String describle = "我是人,不是神";
//构造器
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//方法
public void eat(){
System.out.println("人需要吃饭!\n");
}
//静态代码块
static{
System.out.println("HelloWorld! Good");
}
//非静态代码块
{
System.out.println("HelloWorld! God");
}
//静态方法
public static void print(){
System.out.println("Hello");
}
}
抽象类:
abstract关键字的使用:
-
abstract:抽象的
-
abstract可以用来修饰类的结构:类、方法
-
abstract修饰类:抽象类
- 此类不能实例化
- 抽象类中一定有构造器,便于子类实体化时调用(涉及:子类对象实体化的全过程)
- 开发中,都会提供抽象类的子类,让子类对象实体化,完成相关操作
-
abstract修饰方法:抽象方法
- 抽象方法只有方法的声明,没有方法体
- 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
- 若子类重写了父类中所有的抽象方法后,此子类方可实体化。
- 若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,即abstract类
abstract使用的注意点:
- abstract不能用来修饰:属性、构造器等结构
- abstract不能用来修饰私有方法、静态方法、final的方法、final的类
练习:
public class Test014 {
public static void main(String[] args) {
//多态
Employee manager = new Manager("小明",10001,6000,50000);
manager.work();
CommonEmployee commonEmployee = new CommonEmployee();
commonEmployee.work();
}
}
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();
}
class Manager extends Employee{
private double bonus;//奖金
public Manager(String name, int id, double salary, double bonus) {
super(name, id, salary);
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("管理员工,提供公司运行效率\n");
}
}
class CommonEmployee extends Employee{
@Override
public void work() {
System.out.println("员工正在一线生产车间生产产品\n");
}
}
模板方法:
public class TemplateMethod {
public static void main(String[] args) {
SubTemplate subTemplate = new SubTemplate();
subTemplate.spendTime();
}
}
abstract class Template{
//计算某段代码执行所需要花费的时间
public void spendTime(){
long start = System.currentTimeMillis();
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 judge = true;
for(int j=2;j<=Math.sqrt(i);j++){
if(i%j==0){
judge = false;
break;
}
}
if(judge){
System.out.println(i);
}
}
}
}
接口
一方面, 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都支持USB连接。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系。接口的本质是契约,标准,规范,就像我们的法律一样,制定好后大家都要遵守。
接口的使用:
-
接口使用interface来定义
-
Java中,接口和类是并列的两个结构
-
如何定义接口:定义接口中的成员
-
JDK7及以前:只能定义全局常量和抽象方法
-
全局常量:public static final的,书写时,可以省略不写
-
抽象方法:public abstract的
- JDK8:除了定义全局变量和抽象方法之外,还可以定义静态方法、默认方法(略)
JDK8新特性:
知识点1:接口中定义的静态方法,只能通过接口来调用
知识点2:通过实现类的对象,可以调用接口中的默认方法。
如果实现类重写了接口的默认方法,调用时,仍然调用的是重写以后的方法
知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。 --->类优先原则
知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,'那么在实现类没有重写此方法的情况下,报错。 --->接口冲突 解决方法:在实现类中重写此方法
- 接口不能定义构造器,意味着接口不可以实体化
- Java开发中,接口通过让类去实现**(implements)**的方式来使用.
- 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
- 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
- Java类可以实现多个接口 —> 弥补了Java单继承性的局限性
- 格式: class AA extends BB implements CC,DD,EE
- 接口与接口之间可以实现多继承
- 接口的具体使用:体现多态化
- 接口:实际上可以看做是一种规范
面试题:
抽象类和接口的异同:
相同点:不能实体化;都可以包含抽象方法
不同点:1.把抽象类和接口(java7,java8,java9)的定义、内部结构解释说明
- 类:单继承性 接口:多继承性 类与接口:多实现
public class Test015 {
public static void main(String[] args) {
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
Plane plane = new Plane();
plane.fly();
}
}
interface Attackable{
void attack();
}
interface Flyable{
//全局变量
public static final int MAX_SPEED = 7900;//第一宇宙速度
//省略了public static final
int MIN_SPEED = 1;
//抽象方法
public abstract void fly();
//省略了public abstract
void stop();
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("飞机起飞!");
}
@Override
public void stop() {
System.out.println("飞机降落!");
}
}
abstract class Kite implements Flyable{
}
class Bullet implements Flyable,Attackable{
@Override
public void attack() {
}
@Override
public void fly() {
}
@Override
public void stop() {
}
}
//***************************************************
interface AA extends Flyable{
}
interface BB extends AA{
}
interface CC extends AA,BB{
}
练习:
public class Test017 {
public static void main(String[] args) {
ComparableCircle comparableCircle1 = new ComparableCircle(3.4);
ComparableCircle comparableCircle2 = new ComparableCircle(3.6);
int n = comparableCircle1.compareTo(comparableCircle2);
if (n >0) {
System.out.println("comparableCircle1对象大");
}else if(n<0){
System.out.println("comparableCircle2对象大");
}else{
System.out.println("对象一样大");
}
}
}
interface CompareObject{
//若返回值是0,代表相等;若为正数,代表当前对象大;负数代表当前对象小
public int compareTo(Object object);
}
class Circle{
private double redius;
public double getRedius() {
return redius;
}
public void setRedius(double redius) {
this.redius = redius;
}
public Circle(double redius) {
this.redius = redius;
}
public Circle() {
}
}
class ComparableCircle extends Circle implements CompareObject{
public ComparableCircle(double radius){
super(radius);
}
@Override
public int compareTo(Object object) {
if(this == object){
return 0;
}
if(object instanceof ComparableCircle){
ComparableCircle comparableCircle = (ComparableCircle) object;
if(this.getRedius()>comparableCircle.getRedius()){
return 1;
}else if(this.getRedius()<comparableCircle.getRedius()){
return -1;
}else{
return 0;
}
}else{
throw new RuntimeException("传入的数据类型不匹配!");
}
}
}
代理模式:
public class Test016 {
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface Network{
public void browse();
}
//被代理类
class Server implements Network{
@Override
public void browse() {
System.out.println("访问网络");
}
}
//代理类
class ProxyServer implements Network{
private Network network;
public ProxyServer(Network network){
this.network = network;
}
public void check(){
System.out.println("联网之前检查工作");
}
@Override
public void browse() {
check();
network.browse();
}
}
内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
在Java中, 允许一一个类的定义位于另一个类的内部,前者称为内部类,后者 称为外部类。
Inner class-般用 在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。 ➢Innerclass的名字不能与包含它的外部类类名相同;
分类:成员内部类(static成员内部类和非static成员内部类) **局部内部类(**不谈修饰符)、匿名内部类
类的内部成员之五:内部类
-
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
-
内部类的分类:成员内部类 vs 局部内部类(方法类、代码块内、构造器类)
-
成员内部类:
一方面,作为外部类的成员:
- 调用外部类的结构
- 可以被static修饰
- 可以被四种不同的权限修饰
另一方面,作为一个类:
- 类内可以定义属性、方法、构造器、
- 可以被final修饰,表示此类不能被继承
- 可以被abstract修饰
-
关注:
- 如何实例化成员内部类的对象
import Test07.Person.brain; public class Test018 { public static void main(String[] args) { Person person = new Person("小明",18); Person.lung.breathe(); //创建静态内部类 Person.brain brain = new Person.brain(); brain.think(); //创建非静态内部类 Person.eyes eyes = person.new eyes(); eyes.view(); } } class Person{ private String name; private int age; class heart { private double rate;//心脏跳动的频率 public double getRate() { return rate; } public void setRate(double rate) { this.rate = rate; } public void jump(double rate){ System.out.println("心脏以"+this.rate+"速率跳动"); } } class lung{ public static void breathe(){ System.out.println("肺部可以自主呼吸为身体供氧"); } } static class brain{ public void think(){ System.out.println("大脑会思考!"); } public static void imagine(){ System.out.println("大脑会幻想"); } } class eyes{ public void view(){ System.out.println("眼睛可以看见外面的世界"); } } public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } 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; } }- 如何在成员内部类中区分调用外部类的结构
xxx //方法的形参 this.xxx //内部类的属性 Xxx.this.xxx //外部类的属性(Xxx为外部类名)- 开发中,局部内部类的使用
//返回一个实现了Comparable接口的类的对象 public Comparable getcomparable( ){ //创建一个实现了Comparable接口的类:局部内部类 //方式一: class MyComparable implements Comparable{ @override public int compareTo(object o) { return e; } } return new MyComparable(); } //方式二: return new Comparable(){ @override public int compareTo(Object o){ return 0; } }; }-
在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)时,要求此局部变量声明为final的
public void method(){ //局部变量 int num = 10;//java8新特性(默认自动生成final),Java8以前这样写会报错(要求此局部变量显式的声明为final的 ) class AA{ public void show(){ // num = 20; System.out.println(num); } } }
异常处理:
异常概述与异常
Error:1. 栈溢出:java.lang.StackOverlowError
- 堆溢出:java.lang.OutOfMemoryError
Exception:
异常的处理:
一、抓抛模型
过程一:“抛”:程序在正常执行过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。并将此对象抛出。一旦抛出对象以后,其后的代码不再执行
关于异常对象的产生:① 系统自动生成的异常对象 ②手动生成一个异常对象,并抛出(throw)
过程二:“抓”:可以理解为异常的处理方式:① try - catch - finally ② throws
public static void main(String[] args) {
try {
Student student = new Student();
student.regist(-1001);
} catch (Exception e) {
System.out.println(e.getMessage());//打印异常信息
}
}
class Student{
private int id;
public void regist(int id) throws Exception {
if(id>0){
this.id = id;
}else{
//手动抛出异常
throw new Exception("输入数据无效!");
}
}
}
二、try - catch - finally的使用
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}
……
finally{
//一定会执行的代码
}
说明:
- finally是可选的。
- 使用try将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配
- 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理,一旦处理完成,就跳出当前的try - catch结构(在没有写finally的情况),继续执行其后的代码
- catch中的异常类型如果没有子父类关系,则无先后顺序关系。catch中的异常类型如果满足子父类关系,则要求子类一定要声明在父类上面,否则会报错
- 常用的异常对象处理的方式:① String getMessage()(说明异常出现的原因) ② printStackTrace()(打印输出异常出现位置)
- 在try结构中声明的变量,在出了try结构以后,就不能再被调用
- try - catch - finally结构可以相互嵌套
体会:
- 使用try - catch - finally处理编译时异常,是程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try - catch - finally将一个编译时可能出现的异常,延迟到运行时出现
- 开发中,由于运行时异常比较常见,所以通常不针对运行时异常编译try - catch - finally了。针对于编译时异常,一定要考虑异常的处理。
try - catch - finally中finally的使用:
- finally是可选的
- finally中声明的是一定会被执行的代码,即使catch中又出现异常了,try中有return语句,catch中有return语句等情况
- 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动回收的,我们需要手动的进行资源的释放。此时的资源释放,就需要声明在finally中
三、throws + 异常类型
-
"throws +异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象, 此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码,就不再执行!
-
try-catch-finally :真正的将异常给处理掉了***(此处理治标不治本,并未从源头上解决异常,而是以另一种形式展示异常)***,throws的方式只是将异常抛给了方法的调用者。并没有真正将异常处理掉。
-
开发中如何选择使用==try-catch-finally==还是使用==throws==?
3.1==如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果 子类重写的方法中有异常,必须使用try-catch-finally方式处理。==
3.2==执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throw的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。==
自定义异常
如何自定义异常类?
- 继承于现有的异常结构:RuntimeException、Exception
- 提供一个全局变量:==serialVersionUID==
- 提供重载构造器
public static void main(String[] args) {
try {
Student student = new Student();
student.regist(-1001);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
class Student{
private int id;
public void regist(int id) throws MyException {
if(id>0){
this.id = id;
}else{
//手动抛出异常
throw new MyException("输入数据无效!");
}
}
}
class MyException extends Exception{
static final long serialVersionUID = -3390882787877454L;
public MyException(){
}
public MyException(String message){
super(message);
}
}