java基础(2)-基础类型和语法(static、内部类、final、抽象类、接口、封装)(并将这些基础知识与java的三大特征关联(继承、多态、封装))

本文深入探讨了Java中的关键概念,包括变量作用范围、类型、基本数据类型、静态成员及内部类等,辅以详尽的示例说明,旨在帮助读者全面掌握Java的基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >




1、变量及其作用范围?

   答:3种

2 、java变量分哪几种大的类型?

答:2种

3、java包含哪些基本数据类型和包装类?

答:8种

4、理解java中的装箱和拆箱

5、static的使用方法    

 static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。

 被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。

 只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。

 其中:static成员变量和成员方法可以被public 与private修饰 ,实际上你需要搞明白,private是访问权限限定,static表示不要实例化就可以使用,这样就容易理解多了。static前面加上其它访问权限关键字的效果也以此类推。

static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,可以直接通过类名来访问,访问语法为:
类名.静态方法名(参数列表...)
类名.静态变量名

用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块(用处非常大,呵呵)。

(1)、static变量
 按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。

两者的区别是:
 对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
 对于实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。

所以一般在需要实现以下两个功能时使用静态变量:
l  在对象之间共享值时
l  方便访问变量时

(2)、静态方法
静态方法可以直接通过类名调用,任何的实例也都可以调用,
因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。
因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!!!
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。

例如为了方便方法的调用,Java API中的Math类中所有的方法都是静态的,而一般类内部的static方法也是方便其它类对该方法的调用。

静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的

(3)、static代码块

 static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。例如:

public class Test5{
private static int a;
private int b;

static{
Test5.a=3;
System.out.println(a);
Test5 t=new Test5();
t.f();
t.b=1000;
System.out.println(t.b);
}
static{
Test5.a=4;
System.out.println(a);
}
public static void main(String[] args) {
// TODO 自动生成方法存根
}
static{
Test5.a=5;
System.out.println(a);
}
public void f(){
System.out.println("hhahhahah");
}

运行结果:
3
hhahhahah
1000
4
5

利用静态代码块可以对一些static变量进行赋值,最后再看一眼这些例子,都一个static的main方法,这样JVM在运行main方法的时候可以直接调用而不用创建实例。

(4)、static和final一块用表示什么

static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
对于方法,表示不可覆盖,并且可以通过类名直接访问。

有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static(静态的)就能创建这样的成员。如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。

声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。声明为static的方法有以下几条限制:

它们仅能调用其他的static 方法。

它们只能访问static数据。

它们不能以任何方式引用this 或super(关键字super 与继承有关,在下一章中描述)。
如果你需要通过计算来初始化你的static变量,你可以声明一个static块,Static 块仅在该类被加载时执行一次。下面的例子显示的类有一个static方法,一些static变量,以及一个static 初始化块:
// Demonstrate static variables,methods,and blocks.

class UseStatic {
static int a = 3;
static int b;

static voidmeth(int x) {
System.out.println("x = " + x);
System.out.println("a = " + a);
System.out.println("b = " + b);
}

static {
System.out.println("Static block initialized.");
b = a * 4;
}

public static voidmain(String a

public static voidmain(String args[]) {
meth(42);
}
}

一旦UseStatic 类被装载,所有的static语句被运行。首先,a被设置为3,接着static 块执行(打印一条消息),最后,b被初始化为a*4 或12。然后调用main(),main() 调用meth() ,把值42传递给x。3个println ( ) 语句引用两个static变量a和b,以及局部变量x 。

注意:在一个static 方法中引用任何实例变量都是非法的。

下面是该程序的输出:

Static blockinitialized.
x = 42
a = 3
b = 12
在定义它们的类的外面,static 方法和变量能独立于任何对象而被使用。这样,你只要在类的名字后面加点号运算符即可。例如,如果你希望从类外面调用一个static方法,你可以使用下面通用的格式:

classname.method( )

这里,classname 是类的名字,在该类中定义static方法。可以看到,这种格式与通过对象引用变量调用非static方法的格式类似。一个static变量可以以同样的格式来访问——类名加点号运算符。这就是Java 如何实现全局功能和全局变量的一个控制版本。

下面是一个例子。在main() 中,static方法callme() 和static 变量b在它们的类之外被访问。

class StaticDemo {
static int a = 42;
static int b = 99;
static void callme() {

System.out.println("a= " + a);
}
}

class StaticByName {

public static voidmain(String args[]) {
StaticDemo.callme();
System.out.println("b = " + StaticDemo.b);
}
}

下面是该程序的输出:

a = 42
b = 99

static成员是不能被其所在class创建的实例访问的。

如果不加static修饰的成员是对象成员,也就是归每个对象所有的。

加static修饰的成员是类成员,就是可以由一个类直接调用,为所有对象共有的

 (5)静态类(只能用作内部类)

java允许我们在一个类里面定义静态类。比如内部类(nested class)。把nested class封闭起来的类叫外部类。在java中,我们不能用static修饰顶级类(top level class)。只有内部类可以为static。

     静态内部类和非静态内部类之间到底有什么不同呢?下面是两者间主要的不同。

    a、内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。

    b、非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。

    c、一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

基于上面的讨论,我们可以通过这些特性让编程更简单、有效。

/* 下面程序演示如何在java中创建静态内部类和非静态内部类 */

class OuterClass{

   privatestatic String msg = "GeeksForGeeks";

   // 静态内部类

   publicstaticclass NestedStaticClass{

       //静态内部类只能访问外部类的静态成员

       publicvoid printMessage() {

         // 试着将msg改成非静态的,这将导致编译错误

         System.out.println("Message fromnested static class: " + msg);

       }

    }

    // 非静态内部类

    publicclass InnerClass{

       //不管是静态方法还是非静态方法都可以在非静态内部类中访问

       publicvoid display(){

          System.out.println("Message fromnon-static nested class: "+ msg);

       }

    }

}

class Main

{

    // 怎么创建静态内部类和非静态内部类的实例

    publicstaticvoid main(String args[]){

       //创建静态内部类的实例

       OuterClass.NestedStaticClass printer =new OuterClass.NestedStaticClass();

       //创建静态内部类的非静态方法

       printer.printMessage();  

       //为了创建非静态内部类,我们需要外部类的实例

       OuterClass outer = new OuterClass();       

       OuterClass.InnerClass inner  = outer.newInnerClass();

       //调用非静态内部类的非静态方法

       inner.display();

       //我们也可以结合以上步骤,一步创建的内部类实例

       OuterClass.InnerClass innerObject =new OuterClass().new InnerClass();

       //同样我们现在可以调用内部类方法

       innerObject.display();

    }

}

6、内部类

java提高篇()----详解内部类

可以将一个类的定义放在另一个类的定义内部,这就是内部类。

     内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二)

第一次见面

      内部类我们从外面看是非常容易理解的,无非就是在一个类的内部在定义一个类。

publicclass OuterClass {

    private String name ;

    privateint age;

 

    public String getName() {

        return name;

    }

 

    publicvoid setName(String name) {

        this.name= name;

    }

 

    publicint getAge() {

        return age;

    }

 

    publicvoid setAge(int age){

        this.age =age;

    }

   

    class InnerClass{

        publicInnerClass(){

            name = "chenssy";

            age = 23;

        }

    }

}

      在这里InnerClass就是内部类,对于初学者来说内部类实在是使用的不多,鄙人菜鸟一个同样没有怎么使用过(貌似仅仅只在做swing注册事件中使用过),但是随着编程能力的提高,我们会领悟到它的魅力所在,它可以使用能够更加优雅的设计我们的程序结构。在使用内部类之间我们需要明白为什么要使用内部类,内部类能够为我们带来什么样的好处。

一、为什么要使用内部类

      为什么要使用内部类?在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

      在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

publicinterface Father {

}

publicinterface Mother {

}

publicclass SonimplementsFather, Mother { 

}

 

publicclass DaughterimplementsFather{

    class Mother_implementsMother{  

    }

}

      其实对于这个实例我们确实是看不出来使用内部类存在何种优点,但是如果Father、Mother不是接口,而是抽象类或者具体类呢?这个时候我们就只能使用内部类才能实现多重继承了。

      其实使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,但是如果我们不需要解决多重继承问题,那么我们自然可以使用其他的编码方式,但是使用内部类还能够为我们带来如下特性(摘自《Think in java》):

      1内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

      2在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

      3创建内部类对象的时刻并不依赖于外围类对象的创建。

      4内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

      5内部类提供了更好的封装,除了该外围类,其他类都不能访问。

(1)、内部类基础   

      在这个部分主要介绍内部类如何使用外部类的属性和方法,以及使用.this.new

      当我们在创建一个内部类的时候,它无形中就与外围类有了一种联系,依赖于这种联系,它可以无限制地访问外围类的元素。

publicclass OuterClass {

    private String name ;

    privateint age;

 

    /**省略getter和setter方法**/

   

    publicclass InnerClass{

        publicInnerClass(){

            name = "chenssy";

            age = 23;

        }

       

        publicvoid display(){

            System.out.println("name:" + getName() +"   ;age:" +getAge());

        }

    }

   

    publicstaticvoid main(String[] args) {

        OuterClass outerClass = new OuterClass();

        OuterClass.InnerClass innerClass =outerClass.new InnerClass();

        innerClass.display();

    }

}

--------------

Output:

name:chenssy   ;age:23

      在这个应用程序中,我们可以看到内部了InnerClass可以对外围类OuterClass的属性进行无缝的访问,尽管它是private修饰的。这是因为当我们在创建某个外围类的内部类对象时,此时内部类对象必定会捕获一个指向那个外围类对象的引用,只要我们在访问外围类的成员时,就会用这个引用来选择外围类的成员。

      其实在这个应用程序中我们还看到了如何来引用内部类:引用内部类我们需要指明这个对象的类型:OuterClasName.InnerClassName。同时如果我们需要创建某个内部类对象,必须要利用外部类的对象通过.new来创建内部类: OuterClass.InnerClass innerClass = outerClass.new InnerClass();

      同时如果我们需要生成对外部类对象的引用,可以使用OuterClassName.this,这样就能够产生一个正确引用外部类的引用了。当然这点实在编译期就知晓了,没有任何运行时的成本。

publicclass OuterClass {

    publicvoid display(){

       System.out.println("OuterClass...");

    }

   

    publicclass InnerClass{

        publicOuterClass getOuterClass(){

            returnOuterClass.this;

        }

    }

   

    publicstaticvoid main(String[] args) {

        OuterClass outerClass = new OuterClass();

        OuterClass.InnerClass innerClass =outerClass.new InnerClass();

        innerClass.getOuterClass().display();

    }

}

-------------

Output:

OuterClass...

      到这里了我们需要明确一点,内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.classOuterClass$InnerClass.class

      Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。

(2)、成员内部类

      成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。

      在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

publicclass OuterClass {

    private String str;

   

    publicvoid outerDisplay(){

       System.out.println("outerClass...");

    }

   

    publicclass InnerClass{

        publicvoid innerDisplay(){

            //使用外围内的属性

            str = "chenssy...";

            System.out.println(str);

            //使用外围内的方法

            outerDisplay();

        }

    }

   

    /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */

    public InnerClass getInnerClass(){

        returnnew InnerClass();

    }

   

    publicstaticvoid main(String[] args) {

        OuterClass outer = new OuterClass();

        OuterClass.InnerClass inner =outer.getInnerClass();

        inner.innerDisplay();

    }

}

--------------------

chenssy...

outerClass...

      推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时

(3)、局部内部类

      有这样一种内部类,它是嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

      对于局部内部类实在是想不出什么好例子,所以就引用《Think in java》中的经典例子了。

      定义在方法里:

publicclass Parcel5 {

    public Destionation destionation(String str){

        classPDestionationimplements Destionation{

            privateString label;

            privatePDestionation(String whereTo){

                label = whereTo;

            }

            publicString readLabel(){

                returnlabel;

            }

        }

        returnnew PDestionation(str);

    }  

    publicstaticvoid main(String[] args) {

        Parcel5 parcel5 = new Parcel5();

        Destionation d = parcel5.destionation("chenssy");

    }

}

      定义在作用域内:

publicclass Parcel6 {

    privatevoid internalTracking(boolean b){

        if(b){

            classTrackingSlip{

                privateString id;

                TrackingSlip(String s) {

                    id = s;

                }

                String getSlip(){

                    return id;

                }

            }

            TrackingSlip ts = new TrackingSlip("chenssy");

            String string = ts.getSlip();

        }

    }

    publicvoid track(){

        internalTracking(true);

    }   

    publicstaticvoid main(String[] args) {

        Parcel6 parcel6 = new Parcel6();

        parcel6.track();

    }

}

(4)、匿名内部类

      在做Swing编程中,我们经常使用这种方式来绑定事件

button2.addActionListener( 

                newActionListener(){ 

                    public void actionPerformed(ActionEvent e) { 

                       System.out.println("你按了按钮二"); 

                    } 

                });

      我们咋一看可能觉得非常奇怪,因为这个内部类是没有名字的,在看如下这个例子:

publicclass OuterClass {

    public InnerClass getInnerClass(finalint num,String str2){

        returnnew InnerClass(){

            intnumber = num + 3;

            public int getNumber(){

                returnnumber;

            }

        };        /* 注意:分号不能省 */

    }

    publicstaticvoid main(String[] args) {

        OuterClass out = new OuterClass();

        InnerClass inner = out.getInnerClass(2,"chenssy");

        System.out.println(inner.getNumber());

    }

interface InnerClass {

    int getNumber();

}

----------------

Output:

5

      这里我们就需要看清几个地方

        1 匿名内部类是没有访问修饰符的。

         2 new匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。

         3 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final

        4 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。

PS由于篇幅有限,对匿名内部类就介绍到这里,有关更多关于匿名内部类的知识,我就会在下篇博客(java提高篇-----详解匿名内部类)做详细的介绍,包括为何形参要定义成final,怎么对匿名内部类进行初始化等等,敬请期待……

 

(5)、静态内部类

      java提高篇-----关键字static中提到Static可以修饰成员变量、方法、代码块,其他它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

      1 它的创建是不需要依赖于外围类的。

      2 它不能使用任何外围类的非static成员变量和方法。

publicclass OuterClass {

    private String sex;

    publicstatic String name = "chenssy";

    /**

     *静态内部类

     */

    staticclass InnerClass1{

        /*在静态内部类中可以存在静态成员 */

        publicstatic String _name1 = "chenssy_static";

       

        publicvoid display(){

            /*

             *静态内部类只能访问外围类的静态成员变量和方法

             *不能访问外围类的非静态成员变量和方法

             */

            System.out.println("OutClassname :" + name);

        }

    }

    /**

     * 非静态内部类

     */

    class InnerClass2{

        /*非静态内部类中不能存在静态成员 */

        publicString _name2 = "chenssy_inner";

        /*非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */

        publicvoid display(){

            System.out.println("OuterClassname:" + name);

        }

    }

    /**

     * @desc外围类方法

     * @authorchenssy

     * @data 2013-10-25

     * @return void

     */

    publicvoid display(){

        /*外围类访问静态内部类:内部类. */

        System.out.println(InnerClass1._name1);

        /*静态内部类 可以直接创建实例不需要依赖于外围类 */

        newInnerClass1().display();

       

        /*非静态内部的创建需要依赖于外围类 */

        OuterClass.InnerClass2 inner2 =new OuterClass().new InnerClass2();

        /*方位非静态内部类的成员需要使用非静态内部类的实例 */

        System.out.println(inner2._name2);

        inner2.display();

    }

   

    publicstaticvoid main(String[] args) {

        OuterClass outer = new OuterClass();

        outer.display();

    }

}

----------------

Output:

chenssy_static

OutClass name:chenssy

chenssy_inner

OuterClass name:chenssy

      上面这个例子充分展现了静态内部类和非静态内部类的区别。

7     Final类、方法和变量

(1)  

Final 类不能继承,fianl类下的所有方法都为fianl的,因此声明方法时可以不写此修饰符;

(2)  方法

Final 方法不能被子类覆盖;

因此fianl可以提高程序的运行效率,因为java在运行程序时,先是在本类中寻找方法的,如果找不到就可以在父类中一级一级寻找,用fianl限定方法,程序可以直接找到该方法执行就可以了。可以将该方法可执行字节码直接放到调用他的程序中。

(3)  变量

        Fianl变量称为常量,因为它们的值不会改变。

       限定符final通常与static一起使用。

8 面向对象主要有三大特性: 继承和多态、 封装 。

(1)、抽象类

在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它 只有声明,而没有具体的实现 。抽象方法的声明格式为:

abstract void fun();

抽象方法 必须用 abstract关键字进行修饰 。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为 抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。 抽象类的声明格式如下:

public  abstract class ClassName {
    abstract void fun();
}

下面要注意一个问题:在《JAVA编程思想》一书中,将抽象类定义为“包含抽象方法的类”,但是后面发现如果一个类不包含抽象方法,只是用abstract修饰的话也是抽象类。也就是说抽象类不一定必须含有抽象方法。个人觉得这个属于钻牛角尖的问题吧,因为如果一个抽象类不包含任何抽象方法,为何还要设计为抽象类?所以暂且记住这个概念吧,不必去深究为什么。

在面向对象领域由于抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的 抽象类是不能实例化的 。同时,抽象类体现了数据抽象的思想,是实现多态的一种机制。它定义了一组抽象的方法,至于这组抽象方法的具体表现形式由派生类来实现。同时抽象类提供了继承的概念, 它的出发点就是为了继承,否则它没有存在的任何意义 。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

使用抽象类时应注意一下几点:

a、包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法

b、如果一个非抽象类继承了抽象类,则非抽象类必须实现抽象父类的 所有抽象方法

c、子类中的抽象方法不能与父类的抽象方法同名

d、抽象类不能创建实体,因为抽象类存在抽象方法,而抽象方法没有实体,创建对象后,抽象对象调用抽象方法是没有意义的

e、 抽象类中一定有构造函数。主要为了初始化抽象类中的属性。通常由子类实现

f、final 和 abstract 是否可以同时修饰一个方法,因为用final修饰后, 修饰 类 代表不可以继承 , 修饰 方法 不可重写, 

abstract 修饰类就是用来被继承的,修饰方法就是用来被重写的abstract不能与private修饰同一个方法,因为privte成员对外是不可见的,只能在本类中使用,这样子类就无法重写抽象方法abstract不能与static修饰同一个方法,static 修饰的方法可以用类名调用,而 对于 abstract 修饰的方法没有具体的方法实现,所有不能直接调用

(2)抽象类与接口

接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象,而没有具体的实现,接口本身不是类。 同时实现该接口的实现类必须要实现该接口的所有方法,通过使用implements关键字,他表示该类在遵循某个或某组特定的接口,同时也表示着“interface只是它的外貌,但是现在需要声明它是如何工作的”。

接口是抽象类的延伸,java为了了保证数据安全是不能多重继承的,也就是说 继承只能存在一个父类 ,但是接口不同, 一个类可以同时实现多个接口 ,不管这些接口之间有没有关系,所以接口弥补了抽象类不能多重继承的缺陷,但是推荐继承和接口共同使用,因为这样既可以保证数据安全性又可以实现多重继承。接口声明形式如下:

public  interface InterfaceName {

}

在使用接口过程中需要注意如下几个问题:

a、一个Interface的方所有法访问权限自动被声明为public。确切的说 只能为public ,当然你可以显示的声明为protected、private,但是编译会出错!

b、 接口中定义的所有变量默认是 public static final 的,即静态常量既然是常量,那么定义的时候必须 赋值 , 可以通过接口名直接访问:ImplementClass.name。

c、 接口中定义的方法不能有方法体。接口中定义的方法默认添加 public abstract

d、有抽象函数的不一定是抽象类,也可以是接口类。

e、由于接口中的方法默认都是抽象的,所以接口不能被实例化。

f、类实现接口通过implements实现,实现接口的非抽象类必须要实现该接口的 所有方法 ,抽象类可以不用实现。

g、 如果实现类要访问接口中的成员,不能使用 super 关键字。因为两者之间没有显示的继承关系,况且接口中的成员成员属性是静态的

h、接口没有构造方法。

i、 不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用(refer to)一个实现该接口的类的对象。可以使用 instanceof 检查一个对象是否实现了某个特定的接口。

例如:if(anObject instanceof Comparable){}。

j、在实现多接口的时候一定要避免方法名的重复。

(3)抽象类和接口的区别

a、语法层面上的区别

1)抽象类可以提供成员方法的实现细节(即普通方法),而接口中只能存在public abstract 方法;

2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

4)一个类只能继承一个抽象类,而一个类却可以实现多个接口, Java是单继承,多实现 。

b、设计层面上的区别

1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。

2) 抽象类所体现的是一种继承关系,而继承是一个 “is-a”的关系,而 接口 实现则是 “has-a”的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系。 比如:将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),对于不同种类的鸟直接继承Bird类即可,而鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

3) 设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。 对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

(4)、继承

继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。

继承的特点:

a、子类拥有父类非private的属性和方法

b、子类可以拥有自己属性和方法,即子类可以对父类进行扩展

c、子类可以用自己的方式实现父类的方法( 方法重写 )

d、 构造函数不能被继承

e、 继承使用 extends 关键字实现

重写overriding

父类与子类之间的多态性, 对父类的函数进行重新定义 。如果在子类中定义某方法与其父类有 相同的名称和参数 ,我们说该方法被重写。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称 方法覆盖; 
若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。 那么子类的对象如果调用该函数,一定调用的是重写过后的函数。如需父类中原有的方法,可使用 super 关键字,该关键字引用了当前类的父类; 
子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类,不 能返回比父类更大的数据类型 ;

子类函数的访问修饰权限不能少于父类的; 
子类无法重写父类的private方法 
子类对象查找属性或方法时的 原则:就近原则。

如果子类的对象调用方法,默认先使用 this 进行查找,如果当前对象没有找到属性或方法,找当前对象中维护的 super 关键字指向的对象,如果还没有找到编译报错,找到直接调用。

重载 overloading

方法重载是 让类以统一的方式处理不同类型数据 的一种手段。多个同名函数同时存在,具有 不同的参数个数/类型 。重载是一个类中多态性的一种表现; 
Java 的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性; 
重载的时候,方法名要一样,但是参数类型和个数不一样, 返回值类型可以相同也可以不相同, 无法以返回型别作为重载函数的区分标准; 
所有的重载函数必须在同一个类中

(5)、多态

多态的定义 :指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用) 
实现多态的技术称为 :动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。 
多态的作用 :消除类型之间的耦合关系。 
现实中,关于多态的例子不胜枚举 。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。 
多态存在的三个必要条件

多态弊端 : 提高扩展性,但是只能使用父类引用指向父类成员。

注意:

在多态的情况下,字符类存在同名的成员(成员变量和成员函数)时,访问的是父类的成员,只有是同名的非静态成员函数时,才访问子类的成员函数;

多态用于 形参 类型时,可以接受多个类型的数据;

多态用于返回类型时,可以返回多个类型的数据,使用了多态的方法,定义的变量类型要与返回的类型一致。

以下面例子来分析多态

public class A {  
    public String show(D obj) {  
        return ("A and D");  
    }  

    public String show(A obj) {  
        return ("A and A");  
    }   

}  

public class B extends A{  
    public String show(B obj){  
        return ("B and B");  
    }  

    public String show(A obj){  
        return ("B and A");  
    }   
}  

public class C extends B{  

}  

public class D extends B{  

}  

public class Test {  
    public static void main(String[] args) {  
        A a1 = new A();  
        A a2 = new B();  
        B b = new B();  
        C c = new C();  
        D d = new D();  

        System.out.println("1--" + a1.show(b));  
        System.out.println("2--" + a1.show(c));  
        System.out.println("3--" + a1.show(d));  
        System.out.println("4--" + a2.show(b));  
        System.out.println("5--" + a2.show(c));  
        System.out.println("6--" + a2.show(d));  
        System.out.println("7--" + b.show(b));  
        System.out.println("8--" + b.show(c));  
        System.out.println("9--" + b.show(d));        
    }  
}  

输出结果为:

1--A and A  
2--A and A  
3--A and D  
4--B and A  
5--B and A  
6--A and D  
7--B and B  
8--B and B  
9--A and D  

首先我们先看一句话: 当超类对象引用变量引用子类对象时, 被引用对象的类型 而不是引用变量的类型决定了调用谁的成员方法, 但是这个被调用的方法必须是在超类中定义过的 ,也就是说被调用的方法必须是 被子类重写的方法 。这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级: this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

对于前半句的意思就是:当父类变量引用子类对象时,在调用成员函数时,应该调用向子类的成员函数,但前提是此函数时被子类重写的函数。

A B C D的继承关系如下: 
图片描述
分析:

对于1和2,B和C属于A的子类,调用a1.show(b),a1.show(b),可以找到A.show(A boj),因为多态情况下,父类做形参时,可以接受其子类的实参。

对于3,直接就可以找到A.show(D odj)。

对于4,本来由于a2引用的是其子类B的一个对象,因此调用的成员函数应为B.show(B obj),但是由于B.show(B obj)不是重写的函数,因此不会调用B.show(B obj)。故将按照优先级,先看this.show(O),而类A里面没有找到show(B obj)方法,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为B,(super)O即(super)B即A,因此它到类A里面找show(A obj)的方法,类A有这个方法, 但是由于a2引用的是类B的一个对象,且B覆盖了A的show(A obj)方法 ,因此最终锁定到类B的show(A obj),输出为”B and A”。

对于5,同样将按照优先级,先看this.show(O),而类A里面没有找到show(C obj)方法,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为C,由于A是C的超类,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是 由于a2引用的是类B的一个对象,且B覆盖了A的show(A obj)方法 ,因此最终锁定到类B的show(A obj),输出为”B and A”。

对于6,同样将按照优先级,先看this.show(O),而类A里面刚好找到了show(D obj)方法,输出为”D and A”.

对于7,可以直接调用this.show(O)。

对于8,同样将按照优先级,先看this.show(O),而类B里面没有找到show(C obj)方法,于是到B的super(超类)找,而类A里面没有找到show(C obj)方法,因此转到第三优先级this.show((super)O),this仍然是b,这里O为C,由于B是C的超类,因此它到类B里面找show(B obj)的方法,因此输出为”B and B”。

对于9,同样将按照优先级,先看this.show(O),而类B里面没有找到show(D obj)方法,于是到B的super(超类)找,而类A里面找到了show(D obj)方法,因此输出为”A and D”。

(6)、封装

封装是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其他对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节(当然也无从知道),但可以通过该对象对外的提供的接口来访问该对象。

使用封装有四大好处:

1、良好的封装能够减少耦合。

2、类内部的结构可以自由修改。

3、可以对成员进行更精确的控制。

4、隐藏信息,实现细节。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值