小 汇总

今天的主要内容是构造方法,static用法,继承,多态,抽象类,接口。由于从今天开始JAVA的学习基本上都是面向对象的内容,虽然这些内容底层的实现是由C++写的编译器实现的,在用法上与C语言已经大相径庭,故不再比较二者的差异。开始阐释JAVA的知识点为主。

构造方法

所谓构造方法,就是在创建对象时自动执行的方法,主要用于对成员变量的初始化,当然也可以用于对运行环境的初始化,如加载驱动等。

空参构造

空参构造即以不传递参数的方式下创建对象。如Demo d = new Demo(); 就是用空参构造的方式创建对象,Demo后面的括号,就是用来传递参数的,当其为空时,便是空参构造。

空参构造方法

在类中编写的通过无参构造创建对象系统自动执行的方法。

空参构造方法没有返回值,连void也没有

空参构造方法与类同名

class Demo_constructor {

public static void main(String[] args) {

    Person p = new Person();

    System.out.println(p.name+"..."+p.age);        //张三...18

    }

}

class Person{

    String name;

    int age;

    public Person(){

          name = "张三";

          age = 18;

    }

}

代码中通过空参构造方法Person(),对类中的name和age赋值为张三和18,在主方法中new一个Person对象的时候没有传递参数,系统自动执行空参构造方法,对象中的name和age便有了初值张三和18;

有参构造方法

当创建对象时传递参数,便自动执行有参构造方法。

有参构造方法与无参大致相同,只需在编写时写上参数列表即可。

class Demo_constructor {

  public static void main(String[] args) {

      Person p = new Person("张三",18);

      System.out.println(p.name+"..."+p.age);        //张三...18

  }

}

class Person{

  String name;

  int age;

  public Person(String name,int age){

      this.name = name;

      this.age = age;

  }

}

当局部变量名与成员变量名的相同时,局部变量会隐藏成员变量,但在开发中常要求见名知意,对于这种情况,可以用this.来引用成员变量,与局部变量区分开来。

在写类的时候,倘若没有写构造方法,系统会自动加上空参构造,如果写了有参构造方法,没写空参构造方法,系统不再加上空参构造,在创建对象时便不可以用空参的方式创建,因此,在写完有参构造方法后尽量将空参构造方法也写上。

static

static是静态的意思,在类中定义static成员变量和static成员方法,这些方法是存放在内存的方法区中,在创建对象的时候,不需对这些变量和方法分配空间,可以达到资源共享的作用。

静态成员变量

静态成员变量由所有对象共享,在一个对象该变量修改后,所有的对象静态变量都会修改,因为他们其实都在引用同一个变量。

class Demo_static {

  public static void main(String[] args) {

      Person p = new Person();

      p.name = "张三";

p.country ="中国";

p.speak();                        //张三...中国

      Person p2 = new Person();

      p2.speak();                        //null...中国

      p2.country = "America";

      p.speak();                        //张三...America

  }

}

class Person{

  String name;

  static String country;        //在c语言的解释中就是将country声明周期延长,实现共享,节省空间资源

  public void speak(){

      System.out.println(name+"..."+country);

  }

}

从代码中可以看到,创建对象p之后,将p的name和country修改为张三和中国,然后创建对象p2,虽然没有对p2的属性进行修改,但由于country是static变量,所以,p2的country也为中国,而非静态变量的name为null。然后p2将其变量country修改为America,p的变量country也变为了America。

静态成员方法

将类中的成员方法修饰为static,可以在不创建对象的情况下对方法进行引用,节省空间。其实主方法public static void main(String[] arg){}中,main就是JVM识别的入口,声明为static就可以在不创建该类的情况下调用主函数。

class ArrayTool {

    private ArrayTool(){};

    //若类只有静态方法,要设置私有构造方法,防止创建对象,浪费内存

    public static int getMax(int[] arr){

        int max = arr[0];

        for (int i = 1;i < arr.length ;i++ ){

            if (arr[i] > max){

                max = arr[i];

            }

        }

        return max;

    }

}

上面定义的类中含有static方法,在主函数中可以不创建该类的对象而直接调用方法

class Array_Test {

    public static void main(String[] args) {

        int[] arr = {11,22,33,44,55};

        int max = ArrayTool.getMax(arr);

        }

}

下面的内存分配图可以帮助我们更好的理解static的机制,了解static各个特点的原理

类中静态变量与静态方法内存分配

注意事项

共性用static,特性用auto

静态变量又叫类变量,非静态变量又叫对象变量

静态变量随类产生和消失,非静态变量随对象产生和消失

静态只能访问静态

继承

有时候类与类之间有很多相同的成员变量和方法,倘若全部都要重写,代码的复用性太低,不利于开发。怎么通过类与类之间的联系,减少代码量?继承由此诞生。

JAVA的继承通过extends实现,实现继承的类成为子类,被继承的类成为父类。子类继承了父类,相同的成员变量和方法不需重写便可使用,大大提高了代码的复用性。

class Demo_extends {

    //让类与类之间产生关系,提高代码的复用性,维护性,也是多态的前提

    public static void main(String[] args) {

        Cat c = new Cat();

        c.color = "白";

        c.legs = 4;

        System.out.println(c.color+"..."+c.legs);

    }

}

class Animal{

    String color;

    int legs;

    public void sleep(){

        System.out.println("sleep");

    }

}

class Cat extends Animal{

}

通过extends关键字,Cat类继承了Animal类,即使Cat中的代码块为空,仍然可以使用Animal中的成员变量和方法。

JAVA不支持多继承,只支持单继承,即一个子类只有一个父类,因为当两个父类中有同名的方式时会造成冲突,造成安全隐患。

JAVA在创建子类对象的时候,会先访问父类的构造方法,在访问子类的构造方法。从继承的设计理念来不难理解为什么要这么做,因为子类继承父类是为了使用父类的资源,所以在构造子类时要访问父类。

class Demo_extends3 {

  public static void main(String[] args) {

      Son s = new Son();            //这是父类构造,这是子类构造

  }                                //在构造子类时会动访问父类构造

}

class Father{

  int num1;

  int num2;

  public Father(){

      System.out.println("这是父类构造");

  }

}

class Son extends Father{

  public Son(){                            //所有的子类构造方法会默认访问父类的无参构造方法

      //super();                            //这是一条语句,没写会自动加上,用来访问父类

      System.out.println("这是子类构造");

  }

}

这种机制在父类对象没有空参构造的时候会出现错误,因为系统默认的super();语句是访问父类的空参构造方法,在这种情况下,要在子类的构造方法中进行处理,即用super语句访问父类的有参构造方法。

class Demo_extends4 {//关于父类没有无参构造的解决方法

  public static void main(String[] args) {

      Son s = new Son(1);

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

      Son s2 = new Son();

  }

}

class Father{

  int num;

  public Father(int num){

      System.out.println("父类有参构造");

  }

}

class Son extends Father{

  public Son(){

      super(1);

      System.out.println("子类无参构造");

  }

  public Son(int num){

      super(num);

      System.out.println("子类有参构造");

  }

}

对于在创建的时候,是否会创建父类对象,因为要调用父类构造方法,需要一个实例对象。网上的答案鱼龙混杂,有说要的,有说不要的。但从我查阅的资料看,在创建子类对象的时候不会创建父类对象。

从内存的使用来看,倘若在创建子类对象的时候创建父类对象,所有的对象都是Object的子类对象,那么内存必然会被各种Object对象充斥,可用内存少之又少,几乎不可能有可用内存。这与我们的显示显然是冲突的。

但是要使用父类构造方法,必须有一个实例,这个实例在哪?在知乎一个回答中看到,父类,子类的实例其实是同一个,也就是说在访问父类方法的时候,将该实例作为父类对象,在访问子类构造方法的时候,又把这个实例当做子类对象。这个实例中有一部分是地址用super表示,是作为父类的储存区,而其余部分是子类的储存区域,地址用this表示。

子类对象内存图

多态

编译和运行的时候产生不同的形态成为多态。

多态前提:要有继承,要有方法重写,要有父类引用子类对象

对于多态编译与运行时类中元素的规则

成员变量: 编译看左边(父类),运行看左边(父类);

成员方法: 编译看左边(父类),运行看右边(子类);  动态绑定

静态方法: 编译看左边(父类),运行看左边(父类);

class Demo_Polymorthic {

  public static void main(String[] args) {

      Father f = new Son();

      System.out.println(f.num);            //10

      f.print();                            //Son

      f.speak();                            //fat

  }

}

class Demo_Polymorthic {

  public static void main(String[] args) {

      Father f = new Son();

      System.out.println(f.num);            //10

      f.print();                            //Son

      f.speak();                            //fat

  }

}

class Father{

  int num = 10;

  public void print(){

      System.out.println("Father");

  }

  public static void speak(){

      System.out.println("fat");

  }

}

class Son extends Father  {

  int num = 5;

  public void print(){

      System.out.println("Son");

  }

  public static void speak(){

      System.out.println("so");

  }

}

多态的好处与应用场景

在方法中,父类对象用作参数,子类方法重写,使得代码的复用性提高

class Demo_Polymorthic3 {

  public static void main(String[] args) {

      make(new Dog());

      make(new Cat());

  }

  public static void make(Animal a){        //多态常应用于父类作参数,子类方法重写的应用场景

      a.eat();

  }

}

class Animal{

  void eat(){

      System.out.println("动物吃饭");

  }

}

class Cat extends Animal{

  void eat (){

      System.out.println("猫吃鱼");

  }

  void catchmouse(){

      System.out.println("捉老鼠");

  }

}

在多态的情况下,当父类引用要使用子类特有的方法,要将父类引用强制转换向下转型。以下例子也许可以方便理解和记忆。

class Demo_Polymorthic2 {

  public static void main(String[] args) {

      Person p = new SuperMan();

      System.out.println(p.name);                //man

      p.谈生意();                                //谈几个亿的生意

      //p.fly();                                //p实际上就是子类向上提升

      SuperMan sm = (SuperMan) p;                //向下转型

      sm.fly();

  }

}

class Person{

  String name="man";

  public void 谈生意(){

      System.out.println("谈生意");

  }

}

class SuperMan extends Person{

  String name = "sup";

  public void 谈生意(){

      System.out.println("谈几个亿的生意");

  }

  public void fly(){

      System.out.println("去救人");

  }

}

在上面的代码中,父类引用p 指向子类对象superman,所以在正常引用下,superman就伪装成普通人person,调用成员变量,当然是用伪装的名字man,而当调用成员方法使,实际上就是superman在“”谈生意“,而不是普通的person,故表现其真实的行为,即superman重写的谈生意()这一方法,调用结果是“谈几个亿的大生意”。当要用到superman特有的方法fly()时,必须向下转型成superman,无法再伪装了。

多态内存图解

抽象类

抽象,即无法具体的,所谓抽象类,即用abstract修饰符修饰的类。

abstract 修饰的方法,没有方法体,如 abstarct eat();

抽象类的成员变量不能抽象

抽象类也有构造方法

抽象类的抽象方法使子类必须重写该方法

抽象类可以有非抽象方法,子类可以不重写该方法

抽象类无法创造对象,无法创造出实例,但可以通过多态引用其子类

class Demo_Abstract {

    public static void main(String[] args) {

        Animal a = new Cat();                //通过多态来引用抽象类,抽象类本身无法创造实例

    }

}

abstract class Animal{

    int num1;                                        //抽象类成员变量不能抽象

    final int num2 = 10;

    Animal(){

        System.out.println("抽象类的有参构造");    //抽象类也有构造方法

    }

    abstract void eat();

    public void method(){                        //抽象类可以有非抽象方法,子类继承可以不重写

        System.out.println("抽象类的非抽象方法");

    }

}

class Cat extends Animal{

    void eat(){                                //抽象类使得子类必须重写其抽象方法

        System.out.println("猫吃鱼");

    }

}

抽象类规定了子类必须重写的方法,即规定了子类都必须有的方法,且要求其根据实际重写。

接口

广义上的接口,就是向外提供或者说制定的一种规则,如usb接口,规定了生产接口的厂商应该使用的规格,线路的电压等规则。

在JAVA中接口可以说是抽象类进一步抽象,对实现接口的类制定了特定的规则。

接口没有构造方法

接口所有的都是抽象方法,所以实现接口,就是要重写接口所规定的方法

接口所有的变量和方法都是public,因为接口的目的就是表露其规则,让类去实现,所以权限要足够大。

类实现接口用implements,值得注意的是一个类可以实现多个接口,因为接口的方法都是抽象的,没有方法体,不会产生冲突,这弥补了单继承的缺陷。

接口与接口之间可以继承

class Demo_Interface {

  public static void main(String[] args) {

      InterA a = new Demo();

  }

}

//设计理念,抽象类是为了规定共性的东西,接口是为了实现扩展性

interface InterA{

  public static final int num = 1;    //接口没有构造方法

  public abstract void printA();        //接口的方法都是抽象方法

}

interface InterB{

  void printB();

}

interface InterC extends InterA,InterB{    //接口可以继承接口,并且是多继承

}

class Demo implements InterC {    //类可以实现多个接口

  public void printA(){;}

  public void printB(){;}

}

关于抽象类和接口的设计理念,抽象类规定了子类共同需要重写的方法,是规定了子类的共性,而接口的多实现,可以使类具有扩展性,如下面的例子

class Demo_Interface2 {

    public static void main(String[] args) {

        Cat c = new Cat();

        c.eat();

        JumpCat j = new JumpCat();

        j.eat();

        j.jump();

    }

}

abstract class Animal{

    String name;

    abstract void eat();

}

interface Jump{

    void jump();

}

class Cat extends Animal{

    public void eat(){

        System.out.println("猫吃鱼");

    }

}

class JumpCat extends Cat implements Jump{

    public void jump(){

        System.out.println("跳高");

    }

}

在抽象类Animal中定义了抽象方法eat();因为所有继承他的子类都具有这一行为,必须根据自身重写该方法。而接口Jump定义了jump();这一抽象方法,不同的类根据自己的需求,是否去实现这一接口,去扩展该类的内容。而且由于接口是多实现的,同一个类可以实现不同的接口,展现于其他类不同的行为。

以上便是今天学习的内容中的要点及最应该注意的地方,其中有什么错误的地方,特别是关于内存的分配方面,由于是自己的理解,可能与实际有偏差,希望读者指出并谅解。

               

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,565评论 1 114
  • 序言 人们为什么不遵循自己的“新年计划”? 怎么保证按时上交报告? 为什么有时注重成绩却适得其反? 如何使自己的目...
    ruofeng8阅读 706评论 1 6
  • 这是一个不平凡的九月 1.人民币汇率持续走高,美元兑人民币破6.55 今年年初的时候,美元兑人民币在6.9左右,到...
    福音码字的地方阅读 240评论 3 0