对象
- Java中所有对象都是new出来的,所有对象的内存都是在堆空间,所有保持对象的变量都是引用类型
- Java运行时环境有个垃圾回收器,会自动回收不再使用的内存
一. 构建方法
- 构造方法
- 函数名相同,参数名不同,可以重载
- 构造方法如果想调用别的构造方法,必须放在第一行
- 如果一个类没有自定义构造方法,系统会默认无参构造方法
- 成员变量的初始化
- 编译器会自动为未初始化的成员变量设置初始化值,比如int属性初始化值为0
- 如何手动给实例变量提供初始值?
- 在声明中
- 在构造方法中
- 在初始化块中
- 编辑器会将初始化块复制到每个构造方法的头部(每创建一个实例对象,就会执行一次初始化代码块)
- 如何手动给类变量提供初始值?
- 在声明中
- 在静态初始化块中
当一个类被初始化的时候执行静态初始化块
当一个类第一次被主动使用时,JVM会对类进行初始化
//this,this是一个隐藏的,位置最靠前的方法参数
public class person {
public int age = 10;
protected float weight;
float height;
private float salary;
public static int count;
//set
public void setAge(int age) {
this.age = age;
}
//get
public int getAge() {
return age;
}
//构造
public person() {
age = 10;
weight = 10.f;
height = 50.f;
salary = 10000.f;
}
//初始化代码块 在构造函数前执行
{
weight = 100.f;
height = 100.f;
}
//静态初始化代码块 在构造函数前执行
static {
count = 1;
}
//toString 重写此方法可以打印出对象参数详细信息
@Override
public String toString() {
return "person{" +
"age=" + age +
", weight=" + weight +
", height=" + height +
", salary=" + salary +
'}';
}
public static void main(String[] args) {
person p = new person();
System.out.println(p);
}
}
二. 包
- Java中的包就是其他编程语言中的命名空间,包的本质就是文件夹,常见作用是
- 将不同的类进行组织管理、访问控制
- 解决命名冲突
- 包名写法建议
- com.域名.***
- 包名全小写
- 导包
- #import java.lang.*即导入java.lang当前文件夹下所有文件,不包含其子文件夹下的文件
三. 继承(Inheritance)
- 任何类最终都继承自java.lang.object
- 子类可以定义跟父类同名的成员变量(但不推荐)
public class person {
}
//子类
public class student extends person{
}
四. 方法重写(Override)
- 子类的方法签名与父类一样。也叫做覆盖,重写
- 子类override的方法权限必须≥父类的方法权限
- 子类override的方法返回值类型必须≤父类的方法返回值类型
@Override
public void Method() {
}
五. 注解(Annotation)
- @关键字(值),用于把关键字和值传递给编译器,更精确低控制编译器的动作。关键字都是随技术、框架、编译器的不同而不同,含义也不同、数量不定。可以由子技术或开发者扩充。比如
- @Override:告诉编辑器这是一个重写后的方法
- @SuppressWarnings(“警告类别”),作用:让编译器不生成警告信息;
- @SuppressWarnings({“警告类别”,“警告类别”})
- 比如:@SuppressWarnings(“unused”) 所有unused的警告不会再报了
六. 访问控制(Access Control)
- Java中有4个级别的访问权限,从高到低如下所示
- public:在任何地方都是可见的
- protected:仅在自己的包中、自己的子类(包含其他包)中可见
- 无修饰符/默认修饰符(package-private):仅在自己的包中可见
- private:仅在自己的类中可见
七. static常用来修饰类的成员:成员变量,方法,嵌套类
- 成员变量
- 被static修饰:类变量,静态变量,静态字段
- 在程序运行过程中只占用一份固定的内存(存储在方法区)
- 可以通过实例、类访问
- 没有被static修改:实例变量
- 在每个实例内部都有一份内存
- 只能通过实例访问,不可以通过类访问
- 被static修饰:类变量,静态变量,静态字段
- 方法
- 被static修饰:类方法,静态方法
- 内部不能使用this
- 未被static修饰:实例方法
- 只能使用实例访问
- 被static修饰:类方法,静态方法
public static float height = 180.f;
private static final float count = 10.f;
public static void Mehtod(String[] args) {
}
private static String showName(int count) {
return "name";
}
八. 静态导入
- 使用静态导入后,就可以省略类名来访问静态成员(成员变量、方法、嵌套类)
- 正确使用静态导入,可以消除一些重复的类名,提高代码可读性
- 过度使用静态导入,会让读者分不清静态成员是在哪个类中定义的
- 谨慎使用
package com.mj.other;
public class Test {
public static int age = 1;
public static void show() {
System.out.println("age is" + age);
}
public static class OtherClass {
public void other() {
System.out.println("other");
}
}
}
//导入
package com.mj;
import static com.mj.other.Test.*;
public class main {
public static void main(String[] args) {
System.out.println(age);
show();
OtherClass other = new OtherClass();
other.other();
}
}
//经典使用场景
//Math.PI
package com.mj;
import static java.lang.Math.PI;
public class main {
public static void main(String[] args) {
System.out.println(2*PI*10);
}
}
九. 单例模式
- 饿汉式单例模式
public class Rocket {
//私有的静态的实例变量
private static Rocket instance = new Rocket();
//构造方法私有化
private Rocket() {}
//公共的静态的方法,返回唯一的那个实例
public static Rocket getInstance() {
return instance;
}
}
- 懒汉式单例模式
public class Rocket {
private static Rocket instance = null;
private Rocket() {}
/**
* 这个方法并非线程安全
* 多条线程同时执行
* */
public static Rocket getInstance() {
if (instance == null) {
instance = new Rocket();
}
return instance;
}
}
//调用
Rocket r1 = Rocket.getInstance();
Rocket r2 = Rocket.getInstance();
System.out.println(r1 == r2);
十. _final_常量(constant)
- 被final修饰的类:不能被继承
- 被final修饰的方法:不能被重写
- 被final修饰的属性:只能赋值一次
- 常量(constant)
- 编译器优化:编译时就能确定值的,会直接替换;称为编译时常量
- 常理写法
//大写
private static final int AGE = 1;
public static void main(String[] args) {
System.out.println(AGE);
//直接替换为10,相当于宏替换
System.out.println(10);
}
十一. 嵌套类(Nested Class)
- 嵌套类:定义在另一个类中的类
- 在嵌套类外层的类,称为:外部类(Outer Class)
- 最外层的外部类,称为:顶级类(Top-level Class)
- 内部类:没有被static修饰的嵌套类,非静态嵌套类
- 跟实例变量、实例方法一样,内部类与外部类的实例相关联
- 必须先创建外部类实例,然后再用外部类实例创建内部类实例
- 内部类不能定义除编译时常量以外的任何static成员
- 内部类可以直接访问外部类中的所有成员(即使被声明为private)
- 外部类可以直接访问内部类实例的成员变量、方法(即使被声明为private)
- 跟实例变量、实例方法一样,内部类与外部类的实例相关联
//内部类
public class Person {
private int age = 18;
private float height = 180.f;
public int getAge() {
return age;
}
public class Hand {
private int weight;
//编译时常量 final
private static final double lengths = 0.5;
public void show() {
System.out.println(age);
}
public float showHeight() {
return height;
}
}
}
//调用
public class main {
public static void main(String[] args) {
Person pModel = new Person();
Person.Hand hand = pModel.new Hand();
hand.show();
System.out.println(hand.showHeight());
}
}
- 静态嵌套类:被static修饰的嵌套类
- 静态嵌套类再行为上就是一个顶级类,只是定义的代码写在了另一个类中
- 对比一般的顶级类,静态嵌套类多了一些特殊权限
- 可以直接访问外部类中除实例变量、实例方法外的其他成员(即使被声明为private)
//静态嵌套类
public class Person {
private int age = 18;
private static int count = 100;
private static void run() {
}
public static class Car {
public void doSomethings() {
Person person = new Person();
System.out.println(person.age);
System.out.println(Person.count);
Person.run();
}
}
}
//调用
public class main {
public static void main(String[] args) {
Person.Car car = new Person.Car();
car.doSomethings();
}
}
-
什么情况使用嵌套类?
- 如果类A只用在类C内部,可以考虑将类A嵌套到类C中
- 封装性更好
- 程序包更加简化
- 增强可读性、维护性
- 如果类A需要经常访问类C非公共成员,可以考虑将类A嵌套到类C中
- 另外也可以根据需要将类A隐藏起来,不对外暴露
- 如果需要经常访问非公共的实例成员,设计成内部类(非静态嵌套类),否则设计成静态嵌套类
- 如果必须先有C实例,才能创建A实例,那么可以将A设计为C的内部类
- 如果类A只用在类C内部,可以考虑将类A嵌套到类C中
-
局部类(Local Class):定义在代码块中的类(可以定义在方法中、for循环中、if语句中等)
- 局部类不能定义除编译时常量以为的任何static成员
- 局部类只能访问final或者有效final(有效final:只赋过一次值)的局部变量
- 从Java8开始,如果局部变量没有被第二次赋值,就认定为有效final
- 局部类可以直接访问外部类中的所有成员(即使被声明为private)
public class Person {
private static float height = 180.f;
float count = 10.f;
public void doSomething() {
for (int i = 0; i < 10; i++) {
class ClassA {
int age = 1;
void test() {
//局部类可以获取外部类的有效final属性,即没有再次赋值的属性
System.out.println(height);
System.out.println(count);
}
}
ClassA a = new ClassA();
a.test();
}
}
}
//调用
public class main {
public static void main(String[] args) {
Person person = new Person();
person.doSomething();
}
}
十二. 抽象类(Abstract Class)
- 抽象方法(Abstract Method)
public abstract class AbstractModel {
public abstract void doSomething();
}
- 抽象类:被abstract修饰的类
- 可以定义抽象方法
- 不能实例化,但可以自定义构造方法
- 子类必须实现抽象父类中的所有抽象方法(除非子类也是一个抽象类)
- 可以像非抽象类一样定义成员变量、常量、嵌套类型、初始化块、非抽象方法等
- 也就是,抽象类也可以完全不定义抽象方法
//一级
public abstract class AbstractModel {
public int p1 = 10;
public double p2 = 100.0;
public abstract void test1();
public abstract void test2();
}
//二级
public abstract class AbstractSubModel extends AbstractModel {
@Override
public void test1() {
}
}
//三级
public class ThrAbstractSubModel extends AbstractSubModel{
@Override
public void test1() {
super.test1();
}
@Override
public void test2() {
//TO DO Something
}
}
- 常见使用场景
- 抽取子类的公共实现到抽象父类中,要求子类必须要单独实现的定义成抽象方法
十三. 接口(Interface)
- Java中的接口
- 一系列方法声明的集合
- 用来定义规范、标准
- 接口中可以定义的内容
- 可以定义:抽象方法、常量、嵌套类型,从Java8开始可以定义:默认方法、静态方法(类方法)
- 上诉可以定义的内容都是隐式public的,因此可以省略public关键字
- 从Java9开始可以定义private方法
- 常量可以省略static、final
- 抽象方法不能省略abstract
- 不能自定义构造方法、不能定义(静态)初始化块、不能实例化
- 接口的细节
- 接口名称可以在任何使用类的地方使用
- 一个类可以通过implements关键字实现一个或多个接口
- 实现接口的类必须实现接口中定义的所有抽象方法,除非它是个抽象类
- 如果一个类实现的多个接口中有相同的抽象方法,只需要实现此方法一次
- extends和implements可以一起使用,implements必须写在extends的后面
- 当父类、接口中的方法签名一样时,那么返回值也必须一样。
- 一个接口可以通过extends关键字继承一个或者多个接口
- 当多个父接口中的方法签名一样时,那么返回值类型也必须一样
//1.抽象类 People(人)
public abstract class People {
public abstract void eat();
}
//2.接口 Helperable(助手)
public interface Helperable {
// 常量可以省略static、final
// (public static) int age = 20;
public abstract void Programming(Child child);
public abstract void Shopping(Child child);
void cook(Child child);
}
//3.实现类 老师(Teacher)
public class Teacher extends People implements Helperable {
@Override
public void Programming(Child child) {
System.out.println("Teacher help " + child.getName() + " programming ");
}
@Override
public void Shopping(Child child) {
System.out.println("Teacher help " + child.getName() + " Shopping ");
}
@Override
public void cook(Child child) {
}
@Override
public void eat() {
}
}
//实现类 Rocket(机器人)
public class Rocket implements Helperable {
private Child child;
@Override
public void Programming(Child child) {
System.out.println("Rocket help " + child.getName() + " programming ");
}
@Override
public void Shopping(Child child) {
this.child = child;
System.out.println("Rocket help " + child.getName() + " Shopping ");
}
@Override
public void cook(Child child) {
}
}
//4.调用类 child(儿童)
public class Child {
private String name;
private Helperable helperable;
public Child(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setTelperable(Helperable helperable) {
this.helperable = helperable;
}
public void needHelp() {
helperable.Programming(this);
helperable.Shopping(this);
}
}
//5.main方法调用
public static void main(String[] args) {
Child child = new Child("jack");
child.setTelperable(new Rocket());
child.study();
}
- 抽象类和接口的用途海慧寺有点类似,该如何选择?
- 何时选择抽象类?
- 在紧密相关的类之间共享代码
- 需要除public之外的访问权限
- 需要定义实例变量、非final的静态变量
- 何时选择接口?
- 不相关的类实现相同的方法
- 只是定义行为,不关心具体是谁实现了行为
- 接口升级
- 如果接口需要升级,比如添加新的抽象方法
- 会导致大幅的代码改动,以前实现接口的类都得改动
- 若想在不改动以前实现类的前提下进行接口升级,从java8开始,有2种方案
- 1.默认方法
- 2.静态方法
- 如果接口需要升级,比如添加新的抽象方法
public interface Helperable {
//常量可以省略static、final
// (public static) int age = 20;
// public static int age2 = 20;
public abstract void Programming(Child child);
public abstract void Shopping(Child child);
void cook(Child child);
// 默认方法
// 用default修饰默认方法
// 默认方法只能是实例方法
default void eatable(Child child) {
System.out.println("help " + child.getName() + " eat ");
}
// 静态方法
static void sleepable(String name) {
System.out.println("help " + name + " sleep ");
}
}
十四. 多态(Polymorphism)
- 什么是多态?
- 具有多种形态
- 同一操作作用于不同的对象,产生不同的执行结果
- 多态的体现
- 父类(接口)类型指向子类对象
- 调用子类重写的方法
- JVM会根据引用变量指向的具体对象来调用对应的方法
- 这个行为叫做:虚方法调用(virtual method invocation)
- 类似于C++中的虚函数调用
- instanceof
- 可以通过instanceof判断某个类型是否属于某种类型
十五. 匿名类
后续。。。。