第7章 面向对象(下)
7.1 静态的
1、static:静态的
2、什么是静态的?
和对象无关的,不会因为对象的不同而不同,即所有对象都一样的。
换句话说,和对象无关。
动态的,根据对象的不同而不同,和对象有关,由对象动态决定。
3、static这个关键字用在哪里?
(1)成员变量前面:静态变量
(2)成员方法前面:静态方法
(3)代码块前面:静态代码块
(4)内部类class前面(后面和内部类一起讲):静态内部类
(5)在import语句里面:静态导入
7.1.1 静态变量
4、静态变量
(1)静态变量的定义:是指有static修饰的成员变量
(2)静态变量的特点:
A:静态变量的值是所有对象共享的。
B:虽然可以,但不建议通过“对象.静态变量”的形式进行访问,
建议通过“类名.静态变量”的形式进行访问。
C:如果静态变量的可见性范围被限制了,提供get/set时,它的get/set也是静态的。
在set方法中,静态变量和局部变量(形参)重名了,使用“类名.静态变量”进行区分。
D:静态变量的值是存储在“方法区”中。
//Company公司
public class Employee {
public static String company;//静态变量
public String name;//实例变量
private static String corporation;
public static String getCorporation() {
return corporation;
}
public static void setCorporation(String corporation) {
Employee.corporation = corporation;
//不能使用this.
}
}
public class TestStaticVariable {
public static void main(String[] args) {
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.company = "执影";
System.out.println(e1.company);
System.out.println(e2.company);
// System.out.println(Employee.company);
e2.company = "zhiying";
System.out.println(e1.company);
System.out.println(e2.company);
System.out.println("-----------------");
//静态变量推荐使用“类名.静态变量”的形式进行访问。
Employee.company = "执影人";
System.out.println(Employee.company);
}
}
7.1.2 静态方法
5、静态方法
(1)静态方法的定义:是指有static修饰的方法。
(2)静态方法的特点:
A:静态方法中不允许直接使用本类的非静态成员
B:静态方法中也不允许直接使用this,super等关键字
C:静态方法的调用虽然可以用“对象.静态方法”的形式进行访问,
但是我们更推荐“类名.静态方法”的形式进行访问。
D:父类的静态方法可以被子类访问,但是不能被子类重写
public class Student {
private static String school;
private String name;
public static String getSchool(){
return school;
}
public static void method(){
System.out.println(this.name);//错误,静态方法中不允许出现this
System.out.println(name);//错误,静态方法中不允许直接访问非静态的实例变量name
System.out.println(super.hashCode());//错误,静态方法也不允许出现super
}
}
public class TestStudent {
public static void main(String[] args) {
System.out.println(Math.random());
Student stu = new Student();
System.out.println(stu.getSchool());
//编译器也会处理成Student.getSchool()
System.out.println(Student.getSchool());
}
}
public class Father {
public static void method(){
System.out.println("Father.method");
}
}
/*
@Override:是一个注解。
作用:和编译器说,它标记的方法是子类重写父类的方法。请“严格”按照重写的要求进行格式检查。
如果违反重写的要求,就编译报错。
如果一个方法遵守重写的要求,加或不加@Override都可以。
如果一个方法没有遵守重写的要求,不加@Override有可能编译器不提示你错误,导致和你的意图不一致。
建议:凡是重写的方法,不管你写的对不对,都加@Override。
*/
public class Son extends Father {
//自己以为我重写成功了,但是其实是不对的
/* public static void method(){
System.out.println("Son.method");
}*/
}
public class TestSon {
public static void main(String[] args) {
Father f = new Son();
f.method();//完全等价于Father.method
Father.method();
Son.method();
}
}
7.1.3 静态代码块
6、静态代码块
(1)静态代码块的作用:为类的静态变量初始化
(2)静态代码块的执行特点
A:一个类的静态代码块只会执行一次
B:它是在类加载类初始化时执行,先于类对象的创建
(3)语法结构
【修饰符】 class 类名{
static{
静态代码块
}
}
public class Demo {
static {
System.out.println("静态代码块");
}
public Demo(){
System.out.println("Demo无参构造");
}
}
public class TestDemo {
public static void main(String[] args) {
Demo d1 = new Demo();
Demo d2 = new Demo();
}
}
7.1.4 类初始化
7、类初始化
(1)类初始化:为类的静态变量赋值的过程
(2)类初始化相关代码
A:静态变量声明时,直接=值
B:静态代码块
(3)如果我们编写了类初始化相关代码,那么编译器会给我们
把这些代码按照编写顺序组装到一个<clinit>()的类初始化方法中。
cl:class
init:initialize
(4)一定是先完成类初始化,再进行实例初始化(创建对象),
并且一定是先完成父类初始化,再完成子类初始化。
public class SubDemo extends Demo {
static {
System.out.println("子类SubDemo的静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
/*Demo d1 = new Demo();
Demo d2 = new Demo();
*/
SubDemo s1 = new SubDemo();
SubDemo s2 = new SubDemo();
}
}
7.1.5 静态导入
8、静态导入
(1)静态导入的定义:在import语句里面出现static,就是静态导入
(2)作用:在当前的.java文件中,使用另一个类的静态成员时,可以直接在代码中使用静态成员名,而不用“类名.静态成员名。
import static java.lang.Math.*;
public class TestStaticImport {
public static void main(String[] args) {
/*System.out.println(Math.PI);
System.out.println(Math.random());
System.out.println(Math.sqrt(9));*/
System.out.println(PI);
System.out.println(random());
System.out.println(sqrt(9));
}
}
7.2 抽象类和抽象方法
1、什么是抽象类?
在class前面加abstract修饰的都是抽象类。
【其他修饰符】 abstract class 类名{
}
2、为什么要用抽象类?
(1)不希望你创建这个类的对象,希望你创建它子类的对象(少一点)
(2)当我们在声明某个父类时,其中某些方法不得不声明,但是又无法给出具体的实现,
即无法编写方法体代码,这个方法体代码通常由子类来实现,各个子类的实现不同,
这个时候需要把这样的方法声明为抽象方法,
Java中包含抽象方法的类必须是抽象类(更多的情况)。
3、抽象类的特点
(1)抽象类不能直接new对象,只能new它子类的对象
(2)抽象类中可以包含抽象方法,也可以不包含抽象方法。
但是反过来,包含抽象方法的类,必须是抽象类。
(3)抽象类是用来被继承的,子类继承抽象类时,必须重写抽象类的所有抽象方法,
否则子类也得是抽象类。
4、抽象类和非抽象类有什么区别?
抽象类不能直接new对象,非抽象类可以直接new对象,
抽象类中可以包含抽象方法,非抽象类中不可以包含抽象方法。
5、抽象类中有构造器吗?
一定有
它的构造器存在的意义是被子类调用的。
public abstract class Person {
private String name;
private int age;
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Student extends Person {
//....
}
public class Teacher extends Person {
//.....
}
public class TestPerson {
public static void main(String[] args) {
//做学生信息管理系统
//在整个系统中,要么存在的是学生对象,要么存在的是教师对象
//希望整个程序中不能直接new Person的对象。
Person[] arr = new Person[3];
// arr[0] = new Person();//报错,因为抽象类不允许直接new对象
arr[1] = new Student();
arr[2] = new Teacher();
}
}
//包含抽象方法的类必须是抽象类
public abstract class Graphic {
/*public double area(){
return 0.0;
}*/
//抽象方法,没有方法体,有abstract修饰
public abstract double area();
}
public class Circle extends Graphic {
private double radius;
public Circle() {
}
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public String toString() {
return "Circle{" +
"radius=" + radius +
'}';
}
//不重写报错
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public class Rectangle extends Graphic{
private double length;
private double width;
public Rectangle(){
}
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
@Override
public String toString() {
return "Rectangle{" +
"length=" + length +
", width=" + width +
'}';
}
//不重写报错
@Override
public double area(){
return length * width;
}
}
public class TestGraphic {
public static void main(String[] args) {
Graphic[] arr = new Graphic[2];
arr[0] = new Circle(2.5);
arr[1] = new Rectangle(5,3);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i].area());
/*
arr[i]的编译时是Graphic类型,先要去Graphic类中匹配area()方法,
此时Graphic类中没有area()方法,编译报错。
为了编译通过,必须在Graphic类中,增加area()方法
*/
}
}
}
7.3 注解
7.3.1 基本注解
1、什么是注解?
在代码中,使用@开头的都是注解。
2、注解有什么用呢?
注解也是一种注释,这种注释是代码级别的注释,
它是让另一段代码来读取这个注解,并做出相应的xx操作。
例如:@Override注解。
当编译器(编译器也是一段程序)读取到某个方法上面加了@Override,
就会执行一段代码,这段代码是一段校验该方法是否满足重写要求的判断代码,
如果满足,那么编译通过,
如果不满足,编译器会报错,提醒你违反了重写的要求。
3、3个最最基本的系统注解(JDK1.8之前就有的)
(1)@Override注解
它只能加在重写的方法上面。
(2)@Deprecated注解
它可以用在方法、类、构造器等等上面。
作用:让编译器提醒程序员,如果你使用了这个方法、类、构造器等,编译器会弹出警告,
提醒你这个方法、类、构造器等已经过时了,可能存在设计的缺陷,或者其他问题,
不再推荐你继续使用。
为什么已过时的代码不修复或删掉呢?
修复:修复的成本太高,重新设计一个
开发原则:面向修改关闭,面向扩展开发
删掉:因为这些方法、类、构造器等在旧的项目中还在使用。
比喻:
注销银行卡。
不会删除你之前的所有的银行记录啥,
而是标记为这个卡不能用。
这个操作称为逻辑删除,不是物理删除。
(3)@SuppressWarnings
抑制警告
import java.util.Date;
public class TestDeprecated {
@SuppressWarnings("all")
public static void main(String[] args) {
Date today = new Date(2022-1900,8-1,20);
//使用这个构造器时Date(int year, int month, int date)
//编译器会弹出警告,说,这个方法已过时
System.out.println(today);
//Wed Sep 20 00:00:00 CST 3922
}
}
7.3.2 文档注释
1、Java中有3种注释
(1)单行注释 //
(2)多行注释 /* */
(3)文档注释/** */
文档注释有严格的格式要求。
/**
* 文档注释演示类
* @author Irene
* @version JDK1.8
* @see java.lang.Object
*/
public class TestDoc {
/**
* 这是一个主方法,Java程序的入口
* @param args String[] 它是命令行参数,可以通过java命令传入参数值。格式:java 主类名 参数值1 参数值2 ...
*/
public static void main(String[] args) {
//...
}
/**
* 这是一个求两个整数最大值的方法
* @param a int 第一个整数
* @param b int 第二个整数
* @return int 当a大于b时,返回a的值,否则返回b的值
*/
public static int max(int a, int b){
return a > b ? a : b;
}
/**
* 这是求两个整数的商。
* @param a int 被除数
* @param b int 除数
* @return int 商,a/b的结果,只有整数部分
* @exception ArithmeticException 当b为0时可能发生算术异常
*/
public static int divide(int a, int b){
return a/b;
}
}
7.3.3 JUnit
说明:标准的单元测试编写方式,在实际项目中再讲。
今天,讲单元测试的JUnit的小工具只是把它当成一个代替main方法运行的小工具而已。
使用步骤:
(1)在当前模块中要引入JUnit的库
因为JUnit不是JRE核心类库的一部分,它是第三方的一个工具。
引入的方式很简单:
第一步:先写一个方法
第二步:在方法上面加一个@Test
第三步:@Test会报错,鼠标放到@Test上面,IDEA会提示我们需要引入JUnit的库(一堆class文件)
第四步:单击Add 'JUnit4' to classpath
第五步:下载,默认是下载到C盘用户目录下的.m2的仓库中
(至于后期项目中如何依赖和下载,咱们学习Maven时再学习)
(2)凡是要独立运行的测试方法上面都可以加@Test
使用要求:
(1)自己写的类名,同一个包的所有类,包括当前类,不能命名为Test类。
(2)要使用@Test标记测试方法,
这个测试方法必须是public,void,(),非静态的
(3)@Test标记的测试方法所在类必须只有唯一的无参构造,并且也是public的。
import org.junit.Test;
public class TestJUnit {
@Test
public void test01(){
System.out.println("hello");
}
@Test
public void test02(){
System.out.println("world");
}
}
标签:Java,静态,笔记,class,学习,static,println,public,out
From: https://blog.51cto.com/u_16213911/7089065