目录
案例1:编写一个计算圆面积,要求圆周率为3.14,赋值3个方式都写一下:
一、类变量(静态变量):
(1)定义:
静态对象是放在堆当中,静态域上(jdk7以上)。static变量是同一个类所有对象共享。static类变量,在类加载的时候就生成了
(2)语法:
1.访问修饰符 static 数据类型 变量名;【推荐】 2.static 访问修饰符 数据类型 变量名;
(3)访问:
1.类名,类变量【推荐】 2.对象名.类变量
public class HouseTest {
public static void main(String[] args) {
System.out.println(A.name); //遵守访问权限
}
}
class A {
public static String name = "韩顺平教育";
}
(4)使用细节:
什么时候需要用类变量:当我们需要所有对象都共享一个变量时,就可以考虑使用类变量(静态变量)比如定义学生类,统计所有学生交多少钱
二、类方法
(1)语法:
访问修饰符 staic 返回数据类型 方法名(){}【推荐】, static 访问修饰符 返回数据类型 方法名(){}【推荐】
(2)类方法的调用:
类名.类方法名 或者 对象名.类方法名
(3)使用:
当方法中不涉及到任何和对象相关成员,则可以将方法设计成静态方法,提高开发效率
静态方法,只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员
三、代码块
(1)定义:
代码块:没有方法名,没有参数,只有方法体,而且不通过对象或类显示调用,而是加载类时,或创建对象时隐式调用
语法:【修饰符】{代码} 代码可以写任何语句
代码块的内容在被调用构造器的时候,先去调用构造器
public class HouseTest {
public static void main(String[] args) {
new A("张三");
}
}
class A {
private String name;
public A(String name) {
this.name = name;
System.out.println("我是构造器");
}
{
System.out.println("我是很快被调用的");
}
}
(2)使用细节:
- static代码块也叫静态代码块,作用就是对类经行初始化,而且她随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行。
- 类在new创建对象时加载,创建子类对象时被加载,使用静态成员时被加载
- 普通代码块,在创建对象时,会被隐式的调用,被创建一次,就会调用一次,如果只是使用类的静态成员时,普通代码并不会执行
(3)执行顺序:
1.调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
2.调用普通代码块和普通属性初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通变量初始化,则按他们定义的顺序调用)
3.构造方法最后执行
public class HouseTest {
public static void main(String[] args) {
A a = new A(1);
}
}
class A {
//静态代码块比普通代码块先执行
private int n2 = getN2();
{//普通代码块与普通属性初始化调用的优先级一样谁在前面执行谁
System.out.println("A 普通代码块02");
}
static { //静态代码块与静态属性初始化调用的优先级一样谁在前面执行谁
System.out.println("A 静态代码块01");
}
private static int n1 = getN1();
public static int getN1() {
System.out.println("getN1被调用");
return 100;
}
public int getN2() {
System.out.println("getN2被调用");
return 100;
}
public A(int n2) {
this.n2 = n2;
System.out.println("我最后执行");
}
}
4.构造器的最前面其实隐含了super()和调用普通代码块。
public class HouseTest {
public static void main(String[] args) {
new BB();
}
}
class AA{
{
System.out.println("AA的普通代码块");
}
public AA() {
//1.调用super
//2.调用本类的普通代码块
System.out.println("AA的构造器");
}
}
class BB extends AA{
{
System.out.println("BB的普通代码块");
}
public BB() {
System.out.println("BB的构造器");
}
}
看懂下面这个代码你就知道他们的执行顺序了
package com.dmjxcn.houserent;
public class HouseTest {
public static void main(String[] args) {
new BB();
//执行顺序
//1.AA的getVal01 2.AA的一个静态代码块... 3.BB的getVal03 4.BB的一个静态代码块...
//5.AA的普通代码块 6.AA的getVal02 //7.AA的构造器 8.BB的普通代码块
// 9.BB的getVal04 10.BB的构造器
}
}
class AA {
private static int n1 = getVal01();
static {
System.out.println("AA的一个静态代码块...");
}
{
System.out.println("AA的普通代码块");
}
private int n2 = getVal02();
private static int getVal01() {
System.out.println("AA的getVal01");
return 100;
}
private int getVal02() {
System.out.println("AA的getVal02");
return 100;
}
public AA() {
//1.调用super
//2.调用本类的普通代码块
System.out.println("AA的构造器");
}
}
class BB extends AA {
private static int n3 = getVal03();
static {
System.out.println("BB的一个静态代码块...");
}
{
System.out.println("BB的普通代码块");
}
private int n4 = getVal04();
private static int getVal03() {
System.out.println("BB的getVal03");
return 100;
}
private int getVal04() {
System.out.println("BB的getVal04");
return 100;
}
public BB() {
System.out.println("BB的构造器");
}
}
静态代码块只能调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。(一定要看懂上面的代码)
四、单例设计模式
(1)饿汉式:
public class HouseTest {
public static void main(String[] args) {
GirlFriend instance = GirlFriend.getInstance();
System.out.println(instance.getName());
}
}
class GirlFriend{
private String name;
//为了在静态方法中,返回gf对象
private static GirlFriend girlFriend = new GirlFriend("小红红");
//如何保证我们只能创建一个GirlFriend对象
//1.将构造器私有化
//2.在类的内部直接创建
//3.提供一个公共的static方法返回gf对象
private GirlFriend(String name) {
this.name = name;
}
public static GirlFriend getInstance(){
return girlFriend;
}
public String getName() {
return name;
}
}
(2)懒汉式:
public class HouseTest {
public static void main(String[] args) {
Cat instance1 = Cat.getInstance();
System.out.println(instance1.getName());
Cat instance2 = Cat.getInstance();
System.out.println(instance2.getName());
System.out.println(instance1 == instance2);
}
}
class Cat {
private String name;
private static Cat cat;
//步骤
//1.任然构造器私化
//2.定义一个静态属性
//3.提供一个static方法,可以返回一个Cat对象
private Cat(String name) {
this.name = name;
}
public static Cat getInstance() {
if (cat == null) {
cat = new Cat("小可爱");
}
return cat;
}
public String getName() {
return name;
}
}
二者的区别:饿汉式没用就创建了,懒汉式没有用就不创建。懒汉式不会造成资源浪费,需要才创建(但是有安全风险)
五、final关键字
(1)定义:
- 如果我们要求A类不能被其他类继承,就可以使用final继承
- 如果我们希望自己写的方法只能被继承不能被重写,使用final修饰方法
- 当我们希望某个属性不能被修改或者局部变量不能修改,就用final修饰常量
public class HouseTest {
}
final class A {
}
//class B extends A{}
class C {
public final double PI = 3.14;
public final void h1() {
final int R = 10;
}
}
class D extends C {
// public void h1(){}
}
(2)final定义的赋值:
// 定义的时候赋值 //在构造器中赋值 //在代码块中赋值
public class HouseTest {
public final double P1 = 1.16;
public final double P2;
public final double P3;
{
P3 = 100.0;
}
public HouseTest(double p2) {
P2 = p2;
}
}
//如果final修饰的是静态属性,则初始化位置只能是 定义时 在静态代码块中 不能在构造器中赋值
public class HouseTest {
public static final double P1 = 1.16;
public static final double P2;
static {
P2 = 100;
}
}
final类是可以实例化的,但是不能继承。final的方法是不能重写,但是可以用哦。
一般来说一个类已经是final类了,就不用final修饰了。final不能修饰构造器哦。final和static一起用效率高。包装类都是final修饰的不能被继承
案例1:编写一个计算圆面积,要求圆周率为3.14,赋值3个方式都写一下:
public class HouseTest {
public static void main(String[] args) {
new Circle(10).getArea();
}
}
class Circle {
public double r;
public static final double P1 = 3.14;
public static final double P2;
public final double P3;
static {
P2 = 3.14;
}
public Circle(double r) {
this.P3 =3.14;
this.r = r;
}
public final void getArea(){
System.out.println(this.P3*r*r);
}
}
六、抽象类
(1)定义:
- 用abstract 关键字来修饰一个类时,这个类就叫抽象类;访问修饰符 abstract 类名{ }
- 用abstract 关键字来修饰一个方法时,这个方法就是抽象方法 访问修饰符 abstract 返回类型 方法名(参数列表);
- 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
(2)细节:
- 抽象类不能被实例化
- 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
- 一旦类包含了abstract方法,则这个类必须声明为abstract
- abstract只能修饰类和方法,不能修饰属性和其他的
- 如果一个类继承了抽象类,则它必须继承抽象类的所有抽象方法,除非他自己也声明为abstract类
- 抽象方法不能用private final static修饰,因为你要被别人重写
案例:工人的继承输出工作中
public class Hello {
public static void main(String[] args) {
new Manager("张三",10,10000,1500).work();
new CommonEmployee("李四",9,1000).work();
}
}
abstract class Employee{
private String name;
private int id ;
private double salary;
public Employee(String name, int id, double salary) {
this.name = name;
this.id = id;
this.salary = salary;
}
public abstract void work();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
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("经理"+super.getName()+"工作中");
}
}
class CommonEmployee extends Employee{
public CommonEmployee(String name, int id, double salary) {
super(name, id, salary);
}
@Override
public void work() {
System.out.println("普工"+super.getName()+"工作中");
}
}
七、接口
(1)定义:
接口就是给出一些没有实现的方法,封装到一起,到某个类需要使用的时候,在根据某具体情况把这些方法写出来。
interface 接口名 {属性 ,方法} class 类名 implements 接口{ 自己的属性,自己的方法 , 必须实现的接口的抽象方法 }
在jdk7.0前 接口里的所有方法都没有方法体,即都是抽象方法。jdk8.0之后可以有静态方法,默认方法,也就是说接口中有方法的具体实现
class A implements AInterface{
//如果一个类 implements 实现接口;
//需要将该接口的方法全部都实现
@Override
public void h1() {
System.out.println("你好");
}
}
interface AInterface {
//写属性
public int n1 = 10;
//写方法
//在接口中,抽象方法abstract关键字可以省略
public void h1();
//在jdk8后,可以有默认实现方法,但是需要使用default修饰
default public void ok(){
System.out.println("ok ...");
}
//在jdk8以后可以有静态语法
public static void h2(){
System.out.println("你好啊我是static");
}
}
(2)细节:
- 接口不能被实例化哦
- 接口中的所有方法都被abstract修饰,public哦默认的
- 一个普通类实现接口就要实现全部方法
- 抽象类可以不用实现全部方法
- 一个类可以实现多个接口
- 接口中的属性是public static final 接口中属性的访问 接口名.属性名
- 接口不能继承其他的类,但是能继承其他的接口
(3)接口vs继承:
public class Hello {
public static void main(String[] args) {
LittleMonkey wuKong = new LittleMonkey("悟空");
wuKong.climbing();
wuKong.swimming();
wuKong.flying();
}
}
//小结:当子类继承了父类,就自动拥有父类的功能
//如果子类需要扩展功能就可以通过实现接口功能
//实现接口就是对继承的补充
class Monkey implements Fishable,Birdable{
private String name;
public Monkey(String name) {
this.name = name;
}
public void climbing(){
System.out.println("猴子会爬树");
}
public String getName() {
return name;
}
@Override
public void swimming() {
System.out.println(getName()+"通过学习,可以像小鱼儿一样游泳");
}
@Override
public void flying() {
System.out.println(getName()+"通过学习,可以像小鸟一样飞");
}
}
//接口
interface Fishable{
void swimming();
}
interface Birdable{
void flying();
}
class LittleMonkey extends Monkey{
public LittleMonkey(String name) {
super(name);
}
}
(4)接口的多态特性:
案例:给Usb数组中,存放Phone 和 相机对象,Phone类还有一个特有的方法call(),请遍历Usb数组,如果是Phone对象,除了调用Usb接口定义的方法外,还需调用Phone特有的方法call (向下转型,判断他的运行类型)
public class Hello {
public static void main(String[] args) {
//接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Phone();
usbs[1] = new Camera();
for (int i = 0; i < usbs.length; i++) {
if (usbs[i] instanceof Phone) {
((Phone) usbs[i]).call();
}
usbs[i].work();
}
}
}
interface Usb {
void work();
}
class Phone implements Usb {
public void call() {
System.out.println("可以打电话");
}
@Override
public void work() {
System.out.println("手机工作中");
}
}
class Camera implements Usb {
@Override
public void work() {
System.out.println("相机工作中");
}
}
(5)接口的多态传递现象:
就是接口继承另一个接口,在实现一个接口的类
public class Hello {
public static void main(String[] args) {
IF t1 = new Teacher();
II t2 = new Teacher();
}
}
interface II{}
interface IF extends II{}
class Teacher implements IF{}
八、内部类
类的五大成员是:属性,方法,构造器,代码块,内部类
内部类4种:局部内部类(有类名) 匿名内部类(没有类名,重点!!!) 成员内部类(没用static修饰) 静态内部类使用static修饰
(1)局部内部类:
- 局部内部类定义在方法中/代码块
- 作用域在方法体或者代码块中
- 本质任然是一个类
- 外部其他类不能访问局部内部类(因为局部内部类地位是一个局部变量)
- 如果外部类和局部内部类重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)
public class Hello {
public static void main(String[] args) {
new Outer().m1();
}
}
class Outer{//外部类
private int n1 = 100;
private void m2(){
System.out.println("Outer2");
}
public void m1(){//方法
//1.局部内部类是定义在外部类的局部位置,通常在方法
//2.不能添加访问修饰符,但是可以用final修饰
//3.作用域:仅仅在定义他的方法或代码块中
final class Inner{//局部内部类(本质还是一个类)
private int n1 = 800;
public void f1(){
//4可以直接访问外部类的所有成员,包括私有成员,
//6如果内部类的属性与外部类成员属性重名使用外部类名.this.属性名访问
System.out.println("内部类的n1"+n1);
System.out.println("外部类的n1"+Outer.this.n1);
m2();
}
}
//5.外部类的方法中可以创建Inner对象,然后调用他的方法
new Inner().f1();
}
}
(2)匿名内部类:!!!!!
public class Hello {
public static void main(String[] args) {
new Outer().f1();
}
}
class Outer{
private int n1 = 99;
public void f1(){
//创建一个基于类的匿名内部类
Person person = new Person(){
private int n1 = 100;
@Override
public void hi() {
System.out.println(n1); //就近原则
System.out.println(Outer.this.n1); //访问外部类的同名属性 外部类.this.属性名
System.out.println("匿名内部类重写了 hi方法");
}
};
person.hi();//动态绑定,运行类型是 Outer
//也可以直接调用,匿名内部类本身返回对象 extends Person
new Person(){
@Override
public void ok(String name) {
super.ok(name);
}
}.ok("张三");
}
}
class Person{
public void hi(){
System.out.println("Person hi()");
}
public void ok(String name){
System.out.println("Person hi"+name);
}
}
案例:作为实参传入
public class Hello {
public static void main(String[] args) {
//做实参传递简单高效简洁
f1(new IL() {
@Override
public void show() {
System.out.println("这是一副世界名画");
}
});
//传统写法
f1(new Picture());
}
//静态方法
public static void f1(IL il){
il.show();
}
}
interface IL{
void show();
}
//传统写法(硬编码)
class Picture implements IL{
@Override
public void show() {
System.out.println("这是一符明华");
}
}
案例:简简单单有手就行
public class Hello {
public static void main(String[] args) {
new Cellphone().alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
new Cellphone().alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴们上课了");
}
});
}
}
interface Bell{
void ring();
}
class Cellphone{
public void alarmclock(Bell bell){
bell.ring();
}
}
(3)成员内部类:
public class Hello {
public static void main(String[] args) {
new Outer().t1();
//外部类调用
new Outer().new Inner().say();
}
}
//1.可以直接访问外部类的所有成员,包含私有的
//2.可以添加任意访问修饰符(public,private...)因为他就是一个成员
//3.作用域为整个类的作用域,因为他就是一个属性
//4.外部类访问创建对象然后调用
//5.外部其他类也可以访问
class Outer{ //外部类
private int n1 = 10;
private String name = "张三";
class Inner{//成员内部类
public void say(){
//可以直接访问外部类的所有成员,包含私有的
System.out.println("n1="+n1+"name"+name);
}
}
//写方法
public void t1() {
//使用成员内部类
Inner inner = new Inner();
inner.say();
}
}
(4)静态内部类:
public class Hello {
public static void main(String[] args) {
new Outer().m1();
new Outer.Inner().say();//注意访问修饰符
}
}
class Outer{
private int n1 = 10;
private static String name = "张三";
private static void cry(){}
//放在外部类的成员位置
//使用static 修饰
//可以直接访问外部类的所有静态成员,包含私有的不能访问非静态成员
//可以添加任意访问修饰符
//作用域为整个类体
//外部其他类访问静态内部类
static class Inner{
public void say(){
System.out.println(name);
cry();
}
}
public void m1(){
Inner inner = new Inner();
inner.say();
}
}