面向对象高级--java
- 类变量和类方法
- 类变量
- 什么是类变量
- 类变量的使用细节
- 类方法
- 类方法的使用细节
- 理解main方法和语法
- 深入理解main方法
- 代码块
- 基本介绍
- 使用细节
- 单例设计模式
- 饿汉式
- 懒汉式
- final关键字
- 基本介绍
- 使用细节
- 抽象类
- 使用细节
- 抽象类最佳实践--模板设计模式
- 接口
- 基本介绍
- 注意事项
- 接口和继承对比
- 接口与多态
- 内部类
- 基本介绍
- 四种内部类
- 局部内部类
- 匿名内部类
- 成员内部类
- 静态内部类
类变量和类方法
类变量
类变量又叫做静态变量,关于它存放的位置有不同的说法,但是共识有两点:
1.static变量是同一个类中所有对象共享。
2.static变量在类加载的时候就生成了。
什么是类变量
类变量也叫静态变量或者静态属性,是该类的所有对象共享的一个变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
如何定义类变量:
访问修饰符 static 数据类型 变量名;
静态变量的访问修饰符的访问权限和范围和普通属性是相同的。
如何访问类变量:
类名.类变量名
或者对象名.类变量名
类变量的使用细节
1.类变量是在类加载的时候就初始化了,也就是说,即使没有创建对象,也可以使用类变量。
2.类变量的生命周期是随类的加载开始,随着类消亡而销毁。
类方法
基本介绍:
类方法也叫静态方法。
形式如下:
访问修饰符 static 数据返回类型 方法名(){}
(前提是满足访问修饰符的权限)
类方法的调用:
类名.类方法名
类方法的经典应用场景:
当方法中不涉及任何和对象相关的成员,则可以将方法设计成类方法,这类方法一般是工具,是一些通用的方法,例如:math类,arrays类等等。
类方法的使用细节
1.类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区,类方法中无this的参数,普通方法中隐含着this的参数。
2.类方法中不允许使用和对象有关的关键字,比如this和super,普通方法可以。
3.静态方法只能访问静态成员,非静态方法既可以访问静态成员,也可以访问非静态成员。
(必须遵守访问权限)
理解main方法和语法
深入理解main方法
解释main方法的形式:public static void main(String[] args){ }
1.main方法是虚拟机调用的。
2.java虚拟机需要调用该类的main()方法,所以mian()方法的访问权限必须是public .
2.java虚拟机在执行main()方法时不必调用对象,因此该方法是static。
3.该方法接受String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
main方法同样遵循静态方法的规定,不能调用本类中的非静态成员,如果想要调用,必须先new一个对象,然后通过对象调用。
代码块
基本介绍
代码块又称为初始化块,属于类中的成员,即是类的一部分,类似与方法,将逻辑语句封装在方法体内,通过{}包围起来。
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或者类显式调用,而是加载类时,或创建对象时,隐式调用。
基本语法
修饰符{
代码
};
1.修饰符可写可不写,写的话只能选择static
2.代码块分为两类,使用static修饰的为静态代码块,没有static修饰的为普通代码块。
3.逻辑语句可以为任何逻辑语句。
4. ;可以写上,也可以省略。
代码块的好处:
1.相当于另一种形式的构造器,对构造器的补充,可以做初始化的操作。
2.如果多个构造器中有重复的语句,可以将相同的语句放入代码块中,提高代码的复用性。
使用细节
1.static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次,如果是普通代码块,每创建一个对象,就执行一次。
类什么时候被加载
1.创建对象实例时
2.创建子类对象实例时,父类也会被加载
3.使用类的静态成员时
2.普通代码块在使用类的静态成员时,不会被调用。
3.创建一个对象时,在一个类中调用顺序是:
(1)调用静态代码块和静态属性初始化。(注意:静态代码块和静态属性初始化的调用优先级相同,如果同时存在,则按照它们的顺序执行)。
(2)调用普通代码块和普通属性初始化。(注意:普通代码块和普通属性初始化的调用优先级相同,如果同时存在,则按照它们的顺序执行)。
(3)调用构造方法。
4.构造器的最前面其实隐含了super()和调用普通代码块,静态代码块和静态属性初始化在类加载时就执行完毕了,因此是优于构造器和普通代码块执行的。
5.创建一个子类对象时(继承关系),它们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
1.父类的静态代码块和静态属性初始化。
2.子类的静态代码块和静态属性初始化。
3.父类的普通代码块和普通属性初始化。
4.父类的构造方法。
5.子类的普通代码块和普通属性初始化。
6.子类的构造方法。
单例设计模式
饿汉式
步骤如下:
1.将构造器私有化。
2.在类的内部创建一个对象。
3.向外暴露一个静态的公共方法。
代码如下:
class GirlFriend{
private String name;
private static GirlFriend gf = new GirlFriend("小红");
private GirlFriend(String name) {
this.name = name;
}
public static GirlFriend getInstance(){
return gf;
}
}
这种方式在类加载的时候就创建了一个对象,即使你没有使用这个对象,因此叫做饿汉式。
懒汉式
懒汉式只有在使用者想要使用时才会创建一个对象。
//懒汉式
class Cat{
private String name;
private static Cat cat;
private Cat(String name) {
this.name = name;
}
public static Cat getInstance(){
if(cat == null){
cat = new Cat("小黄");
}
return cat;
}
}
final关键字
基本介绍
final可以修饰类,属性,方法,局部变量。在下列情况下。可能会使用到final:
1.当不希望类被继承时,可以使用final修饰。
2.当不希望父类的某个方法被子类重写时,可以使用final关键字修饰。
3.当不希望类的某个属性或者局部变量的值被修改时,可以使用final修饰。
使用细节
1.final修饰的属性又叫做常量,一般用XX_XX来命名。
2.final修饰的属性定义时必须赋初值,并且以后不能更改,赋值可以在以下几种位置:
(1).定义时
(2).构造器中
(3).代码块中
3.如果final修饰的属性是静态的,则初始化的位置只能是
(1).定义时
(2).静态代码块中
3.如果类不是final类,但是含有final方法,该方法虽然不能够重写,但是可以继承。
4.final不能修饰构造器。
5.final和static往往搭配使用,效率更好,不会导致类加载,因为底层编译器做了优化处理。
6.包装类(String,Double,Float,Boolean)等都是final类,不能被继承。
抽象类
基本介绍:
当父类的某个方法不确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract修饰该类就是抽象类。一般来说,抽象类会有子类继承,通过子类来实现抽象类。
abstract class Dog{
public abstract void eat();
}
使用细节
1.抽象类不能够实例化,即不能创造对象。
2.抽象类不一定要包含abstract方法。
3.一旦包含了abstract方法,这个类必须声明为抽象类。
4.abstract只能修饰类和方法,不能修饰其他的。
5.抽象类中可以有任意成员,它的本质还是类。
6.如果一个类继承了抽象类,那么他必须实现抽象类的所有抽象方法,或者也声明为抽象类。
7.抽象方法不能使用private,final,static来修饰,因为这三个关键字都是和重写违背的。
抽象类最佳实践–模板设计模式
接口
基本介绍
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些类写出来。
语法:
interface 接口名{
//属性
//方法
}
在接口里,抽象方法可以省略abstract
class 类名 implements 接口{
//自己属性
//自己方法
//必须实现接口的抽象方法
}
总结:
在JDK7.0之前,接口里的方法都是抽象方法,
在JDK8.0及之后,接口里可以有静态方法,默认方法,也就是说接口里可以有方法的具体实现。
//默认实现方法需要有default
default public void Hi(){
System.out.println("hi ");
}
注意事项
1.接口不能被实例化。
2.接口中所有的方法是public 方法,接口中抽象方法可以不使用abstract修饰。
3.一个普通类实现接口,必须实现接口中所有的抽象方法。
可以使用快捷键alter+enter
4.如果是抽象类实现接口,可以不用实现接口中的方法。
5.一个类可以同时实现多个接口。
6.接口中的属性,只能是final的,而且是public static final修饰符,比如int n = 1;实际上是public static final int n = 1;(属性必须进行初始化)
7.接口中的属性的访问形式(接口名.属性名)
8.接口不能继承其他的类,但是可以继承其他的多个接口。(extends)
9.接口的修饰符只能是public 和默认,这点和类的修饰符是相同的。
10接口中的属性访问
interface A{
int n =1;
}
class B implements A{
}
main方法中{
B b = new B();
b.n;
A.n;
B.n;
//这三种方式都可以访问A中的属性
}
接口和继承对比
当子类继承了父类,就自动的拥有父类的功能,如果子类需要扩展功能,可以通过实现接口的方式来扩展,可以理解为,实现接口是对JAVA单继承机制的一种补充。
(1)接口和继承解决的问题不同
继承的价值主要在于:
解决代码的复用性和可维护性。
接口的价值主要在于:
设计,设计好各种规范(方法),让其他类去实现这些方法,即更加的灵活。
(2)接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足like-a的关系
(3)接口在一定程度上实现代码的解耦。
接口与多态
1.接口的多态性
public class interfacePoly {
public static void main(String[] args) {
//接口类型的变量a可以指向实现了接口的类的对象实例
IF a = new A();
a = new B();
}
}
interface IF{}
class A implements IF{}
class B implements IF{}
2.多态数组
public class interFacePolyArr {
public static void main(String[] args) {
usb[] usbs = new usb[2];
usbs[0] = new phone();
usbs[1] = new camera();
for (int i = 0; i < 2; i++) {
usbs[i].work();
if(usbs[i] instanceof phone){
((phone) usbs[i]).call();
}
}
}
}
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("相机工作中");
}
}
3.多态传递
public class interFacePolyPass {
public static void main(String[] args) {
D d = new teacher();
//D继承了C接口,那么就相当于teacher也实现了C接口,可以有下面的定义
C c = new teacher();
}
}
interface C{}
interface D extends C{}
class teacher implements D{}
内部类
基本介绍
一个类的内部又完整的嵌套了另一个类结构,嵌套的类成为内部类,被嵌套的类成为外部类。类的五大成员包括属性,方法,构造器,代码块,内部类,内部类的最大特点就是可以直接访问私有属性,并且可以实现类与类之间的包含关系。
基本语法:
class Outer{ //外部类
class Inner{ //内部类
}
}
四种内部类
局部内部类
定义在外部类局部位置上,比如方法内,有类名。
使用细节:
1.可以直接访问外部类的所有成员,包括私有的。
2.不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的,但是可以使用final修饰,因为局部变量也可以使用final.
3.作用域:仅仅在定义它的方法或者代码块内部。
4.局部内部类—访问—>外部类成员(访问方式:直接访问)
5.外部类—访问---->局部内部类成员
访问方式:创建对象,在访问(注意:必须在作用域内部)
class AA{
private int n1 = 10;
private void m1(){
System.out.println("m1被调用");
}
public void n1(){
class inner{
public int n1 = 100;
public void f1(){
System.out.println(n1);
System.out.println("外部类的n1= " + AA.this.n1);
m1();
}
}
inner inner01 = new inner();
inner01.f1();
}
}
6.外部其它类不能调用局部内部类,因为局部内部类有使用范围.
7.如果外部类和局部内部类的成员重名时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.this.成员名)去访问.
匿名内部类
定义在外部类局部位置上,比如方法内,没有类名。
主要有4点:1.本质还是类 2.内部类 3.该类没有名字 4 .还是一个对象
基本语法:
new 类或者接口(参数列表){
类体
};
class Untitled {
public static void main(String[] args) {
f1 f = new f1();
f.method();
}
}
class f1{
public void method(){
//a的编译类型 A 运行类型 匿名内部类即f1$1
//jdk在底层创建 匿名内部类 f1$1 ,并且立刻创建了它的实例,把地址返回给a
//匿名内部类使用一次就不能再使用,但a可以连续使用
A a = new A(){
public void cry(){
System.out.println("哈哈哈");
}
};
a.cry();
}
}
interface A{
void cry();
}
class Untitled {
public static void main(String[] args) {
f1 f = new f1();
f.method();
}
}
class f1{
public void method(){
//基于类的匿名内部类
Father father = new Father("Jack"){
public void test(){
System.out.println("匿名内部类的test被调用");
}
};
father.test();
}
}
class Father{
public Father(String name){
System.out.println("name= " + name);
}
public void test(){
System.out.println("Father的test被调用");
}
}
使用细节:
1.匿名内部类既是一个类的定义,同时也是一个对象,因此调用匿名内部类的方法有两种情况。
上面的例子是其中一种,下面展示另外一种:
new Father("Jack"){
public void test(){
System.out.println("匿名内部类的test被调用");
}
}.test();
2.可以直接访问外部类的所有成员。
3.不能添加访问修饰符,因为它的地位就是一个局部变量。
4.作用域:仅仅在定义它的代码块或者方法中。
5.外部其它类不能调用匿名内部类,因为匿名内部类有使用范围.
6.如果外部类和匿名内部类的成员重名时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.this.成员名)去访问.
实践:
1.当做实参直接传递,简洁高效。
public class NiMingClass {
public static void main(String[] args) {
Abc(new AB() {//匿名内部类本质上也是一个对象
@Override
public void show() {
System.out.println("这是一幅世界名画");
}
});
}
public static void Abc(AB ab){
ab.show();
}
}
interface AB{
void show();
}
成员内部类
成员内部类是定义在外部类的成员位置,并且没有static修饰
使用细节:
1.可以直接访问外部类的所用成员,包括私有的。
public class MemberOuterClass {
public static void main(String[] args) {
Outer outer = new Outer();
outer.Abc();
//第一种方式
Outer.MemberOuter01 member = outer.new MemberOuter01();
//第二种方式,在外部类写一个方法返回
Outer.MemberOuter01 member01 = outer.t();
}
}
class Outer{
private int n =1;
public String name = "张三";
class MemberOuter01{
public void say(){
System.out.println("n= " + n + " name=" + name);
}
}
public void Abc(){
MemberOuter01 memberOuter01 = new MemberOuter01();
memberOuter01.say();
}
public MemberOuter01 t(){
return new MemberOuter01();
}
}
2.可以添加任意访问修饰符(public ,protected , 默认 , privated ),因为它的地位就是一个成员。
3.作用域:和其它外部类的成员一样,为整个类体。
4.成员内部类访问外部类的成员-----直接访问。
5.外部类访问成员内部类的成员------先创建对象,在进行访问
6.外部其他类访问成员内部类有两种方式,代码如上:
7.如果外部类的成员与内部类的成员名字重复时,内部类访问时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.this.成员名)。
静态内部类
静态内部类是定义在外部类的成员位置,有static修饰。
使用细节:
1.可以直接使用外部类的所有静态成员,包括私有的,但是不能访问非静态成员。
2.可以添加任意访问修饰符,(public , protected , privated , 默认),它的地位就是一个成员。
3.作用域:同其他的成员,为整个类体
4.外部其他类访问静态内部类的方式有两种:
public class StaticInnerClass {
public static void main(String[] args) {
InnerClass.hi innerClass = new InnerClass.hi();
innerClass.say();
System.out.println("========");
InnerClass.hi innerClass02 = new InnerClass().m1();
innerClass02.say();
}
}
class InnerClass{
public int n1 = 10;
public static String name = "李四";
static class hi{
public void say(){
System.out.println(name);
}
}
public hi m1(){
return new hi();
}
}
5…如果外部类的成员与内部类的成员名字重复时,内部类访问时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.成员名)。