《Java7编程高级进阶》(一)

25 篇文章 0 订阅
21 篇文章 0 订阅

数组

是用来存放相同类型的数据。

            int[] a;//需要注意这里是申明数组
            //int[5] a;这种是错的,坚决不可以在申明时指定数组大小。
            a = new int[5];//这里才是创建数组
            int[] b = new int[5];//这种是申明带创建
int[] c = {1,2,3};

该语句声明了包含3个元素的整型数组,编译器会根据花括号内指定的初始化器的数量决定数组的大小,当JVM在内存中加载代码的时候,会自动分配内存位置进行初始化。

这类初始化称之为集初始化,是一种非常安全的用于初始化数组的方法,因为在运行时初始化,比较容易报错。

另外如果有大量的数据,请不要使用这种方式申明,因为Java编译器会创建大量的Java字节码用来初始化数组,最好的方法就是存在外部的文件中,然后在运行的时候,进行读取。

Tip

我们一定要正确规范我们平常代码书写,争取做代码的艺术家,我们要习惯在一些不变的量的时候,创建常量,如果这个值会发生变化,那么只需要修改一处即可。

非矩形数组

在这之前,我们不论是一维数组还是多维数组,最起码都是矩形数组。

这里写图片描述

非矩形数组在分配内存时候,会根据数组的行数先分配几个连续的空间,然后在每一个单元上指向一维数组的引用,下面是具体的代码:

        int[][] a = new int[5][];
        a[0] = new int[5];
        a[1] = new int[2];
        a[2] = new int[1];
        a[3] = new int[7];
        a[4] = new int[9];
        //在引用的时候,还是a[i][j]去引用,注意索引,不要越界。
封装

封装使我们面向对象的三大特点之一,我们private申明符隐藏,通过暴露set、get方法来提供访问。在这里需要提到的一点,我们常常对一些属性值都要要求,比如年龄不能为负,等等。那么这些检验,你就需要在每次赋值的时候,都进行判断,这实际上是很不友好的,我们可以在set方法做出判断,好处就是下次判断修改了,只需要改一处即可。

        private int age;
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            if(age>0) {
            this.age = age;
            }else {
                System.out.println("用户年龄输入不合适!");
            }
        }
构造函数初始化赋值

尽管我们在显示申明某个字段之后,编译器会默认赋予值,但是如果你仍然希望你创建的对象具有初始化的默认值,可以在构造函数中进行赋值,这样一旦构造对象,它就会有默认值。

        public Test36() {
            super();
            age = 10;
            // TODO Auto-generated constructor stub
        }

如果要每次传入属性的值不同,你只需要为构造函数提供不同参数,每次构造的时候,赋不同的值。

记住,只要你提供了自己的构造函数,编译器都不会提供默认的构造函数,如果自己需要用,自己显示声明一下。

package

package语句可以让你将相关的类逻辑性分组到单个独立单元中。

需要注意的地方:

  1. 包必须早于任何其他语句在源文件的开头进行申明。(在源程序的其他地方编写package申明语句会导致编译时错误)
  2. 源文件只允许包含一条声明。
  3. 包名必须为层次结构。(子包必须由点分隔)
  4. 如果没有申明包,编译器会创建默认包,而所有不声明的类都会放到默认包中。(创建的默认包就是当前目录本身)
import

紧接在package声明之后的是import申明,使用import语句可以告诉编译器在编译时去哪里找到源程序需要的外部类。

在import语句中,可以指定类名来导入单个类,通过号,可以导入所有的类,import为编译器指定寻找类的路径。import并不会加载代码,因此带的import语句不会影响程序的运行的性能。

继承

子类拥有父类的属性和方法,除了是私有的。(前提是自爱一个包中)

super关键字,在继承中是常见的,可以用来子类对象访问父类的方法、属性,除了私有(前提是在一个包中)

    public Test38() {
         super();
        // TODO Auto-generated constructor stub
    }

在继承中,我们经常看见一个继承父类的一个方法,经常会自带super(),super( )这个是执行父类的这个方法,需要注意这个必须是在第一行中。如果你在之类不需要执行父类的,删除即可。

在构造函数中,子类继承父类,只有你在构造函数中申明对其他函数的调用,那么不会默认调用父类的构造函数,否则,只要调用子类的构造函数,父类的构造函数按定义的层次去调用,这就是构造函数链。

如果不对super做显示调用,编译器将会提供不带参数的super调用,如果父类没有显示提供无参的构造函数,会编译报错,但是如果父类没有无参有参的构造函数,编译器会调用自己(子类)的无参函数。

supper和this不能同时出现,this和super一样,出现都是在第一行,否则编译出错。

方法重载

就是多个方法,方法名相同,但是方法的参数个数和类型不相同。

构造函数的复制

就是通过在构造函数传入之前构造对象的引用,在进行赋值。

    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Test39(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Test39(Test39 t) {
        this(t.name,t.age);//调用当前对象的构造函数
        //等价于this.name = t.name,this.age = t.age
        // TODO Auto-generated constructor stub
    }
    public static void main(String[] args) {
        Test39 t = new Test39("laoqiang",123);
        Test39 t1 =new Test39(t);
        System.out.println(t1.age+t1.name);
    }
final

根据Java编程习惯,所有final变量都应当以大写字母声明,并且使用下划线字符分隔变量名的单词。

final变量不需要在声明时候初始化,也可以在申明后其他地方初始化,不过,初始化只能执行一次,声明为初始化的final变量叫空缺final变量。最好初始化在构造函数中。

        final Test39 t = new Test39("laoqiang",12232131);
        t.setName("liu");t.setAge(25);
        System.out.println(t.getAge()+t.getName());
        //t = new Test39("sdadsa",12323);被final修饰的对象,
        //只能保证他的引用不能变
        //但是它的对象值是可以改变,可以通过暴露出来的set方法修改
        //如果没有加final,只是这个t对象,引用改变了。
        //注意这种方式和Test39 t1 = new Test39(t);
        //Test39 t1 = new Test39(t);这种是对象重名了。
访问修饰符

这里写图片描述

在继承中,不能使用比父类更弱的权限,最弱private。

static

static 关键字来创建全局访问的变量。静态字段的内存分配仅发生一次,就是在类加载的时候,静态变量在这个类的所有对象中可以共用,静态变量的值的修改,在所有变量中都是可见的。

理解static字段最好的例子:统计构造了多少个对象。

private static int count = 0;
    public static void main(String[] args) {
        Test40 t1 = new Test40();
        Test40 t2 = new Test40();
        Test40 t3 = new Test40();
        Test40 t4 = new Test40();
        Test40 t5 = new Test40();
        Test40 t6 = new Test40();
        Test40 t7 = new Test40();
        System.out.println(count);

    }
    public Test40() {
        super();
        // TODO Auto-generated constructor stub
        count++;
    }

这里写图片描述

在继承中,子类会继承父类的静态变量,可以说是和父类共用一个静态变量。

  • 静态字段属于类而不是对象。非静态变量属于类的实例,因此被称之实例变量。
  • 静态变量只在执行时初始化一次。
  • 静态变量直接类名调用。
静态方法
  • 静态方法是通过类来引用,也可以通过对象来调用,这种是不建议的。
  • 静态方法中是不能this和super关键字。
  • 静态方法中是不能访问非敬爱字段和方法,只能访问静态字段和方法。
  • 静态方法不能被子类重写。
静态初始化器

我们常常用构造函数来初始化类的非静态字段,构造函数在对象创建时被调用,并在对象可用之前完成其中定义的初始化。我们使用同样的构造函数来初始化类的静态字段,在构造函数中初始化静态字段意味着就必须等待对象创建完。在某些情况下,你希望在实例化之前初始化静态字段,这时就必须使用静态初始化器,需要注意只能初始化静态变量。

静态初始化器类似于没有名字、没有参数、没有返回类型。

静态初始化器是在类加载时自动执行的。

静态初始化器仅在加载类的时候执行一次,类可以包含多个静态初始化器,他们按照在类中出现的顺序执行,所以按照一定的顺序组织累的多个逻辑初始化是非常有用的。

注意点:

  1. JVM将静态代码块大小限制64kb,所以不能放太多代码。
  2. 静态代码块中代码,不能抛出检查。
  3. 静态初始化不能使用this,因为还没有实例。
  4. 不能在静态代码块显示调用super,只有对象创建的时候,才可以调。
接口

Java接口类似于协议,提供不同类型或者相同类型对象之间一致同意的行为。

在Java中不包含任何方法的接口被称之为标记接口,例如:Serializable。

接口中的修饰符,只会使public或者默认的。在接口中申明的是常量字段或者是抽象方法,没有方法体,不需要实现。接口默认就是抽象,不需要显示用abstract关键字。

public interface Test44 {
    int age = 100;
    void show();
}

拓展接口:

Java的接口是可以通过extends关键字去拓展接口中方法的能力。

第一个接口:

public interface Test44 {
    int age = 100;
    void show();
}

第二个接口:

public interface Test45 extends Test44 {
    @Override
    default void show() {
        // TODO Auto-generated method stub
        System.out.println("我是拓展接口");
    }

    void look();
}

实现类:

@Override
    public void look() {
        // TODO Auto-generated method stub
        System.out.println("我是实现");
    }
    public static void main(String[] args) {
        Test46 t = new Test46();
        t.look();
        t.show();
    }
抽象类

抽象类的注意点:

  1. 一个抽象类中可以没有一个抽象方法,但是只要有一个就必须将类申明成抽象的。
  2. 抽象类不能被实例化,但是他的子类可以被实例化。
  3. 抽象类除了抽象方法,也可以有方法的实现。
  4. 抽象方法的修饰符应该用public和protected,不能用private,原因子类继承抽象类,但是不继承抽象类的私有的方法。
  5. 抽象函数可以用构造函数。
内部类
  • 静态类

静嵌套类不可以引用外层累的非静态方法

  • 非静态类(成员类)
    • 局部类

定义在方法体内的,被称之为局部类。局部类的作用域就是方法的作用域。同时也可以定义在静态初始化器和构造函数中。

构造函数中的局部类

        public Test54() {
        super();
        // TODO Auto-generated constructor stub
        class inner{
            public void show() {
                System.out.println("我是构造函数中的局部类");
            }
        }
        new inner().show();//直接在构造函数中构造对象,调用对应的方法。
    }
        public static void main(String[] args) {
            Test54 t = new Test54();
        }

方法体中的局部类

    private int a =5;
    public void show(final int b){
        //b = 20;
        //final int d  = 0;
        //d = 50;
        class inner{
            private int c = 20;
            public void test() {
                System.out.println(a);
                System.out.println(b);//这里内部类访问方法的形参或
                //者局部变量,必须申明成final
                System.out.println(c);
                //System.out.println(d);测试内部类访问局部变量,也必须加final
            }
        }
        new inner().test();//直接在方法中进行构造对象,执行相应的方法。
    }

    public static void main(String[] args) {
        Test55 t = new Test55();
        t.show(10);
    }

方法中局部类

    private int a =5;
    public void show(final int b){
        //b = 20;
        //final int d  = 0;
        //d = 50;
        class inner{
            private int c = 20;
            public void test() {
                System.out.println(a);
                System.out.println(b);//这里内部类访问方法的形参或
                //者局部变量,必须申明成final
                System.out.println(c);
                //System.out.println(d);测试内部类访问局部变量,也必须加final
            }
        }
        new inner().test();//直接在方法中进行构造对象,执行相应的方法。
    }

    public static void main(String[] args) {
        Test55 t = new Test55();
        t.show(10);
    }

局部类的注意点:

  1. 局部类仅在自身的代码块中可见和可用,这就是为啥在构造函数和方法里直接构造局部类的对象,进行调用。
  2. 局部类可以访问局部内的任何变量、方法参数、或者是作用域的异常参数,但是他们必须是final修饰。
  3. 局部类不能申明包含static的字段、方法等。
  4. 局部类不能用public、protected、private、static修饰。

    • 匿名类

是在方法体中申明的内部类,没有名称。

具体例子:

    public  abstract class Test57 {
        abstract void eat();
    }
//这里可以是抽象类或者是接口都ok
        public static void main(String[] args) {
        new Test57() {

            @Override
            void eat() {
                // TODO Auto-generated method stub

            }

        };//这里实际匿名构造一个类继承了Test57
    }

匿名类的注意点:

  1. 匿名类不能有构造函数,因为没有与之相关的名字。
  2. 匿名类编译之后,每一个匿名类会产生Outclassname$1.class文件,如果有多个匿名类,更改后面的数字,递加。
内部类可以访问修改外部类的成员变量
   private int count;
       class inner{
           private void setCount() {
               count++;
           }
       }

       public void getCount() {
           System.out.println(count);
       }
       public static void main(String[] args) {
        Test50 t = new Test50();
        Test50.inner ti = t.new inner();
        ti.setCount();
        ti.setCount();
        t.getCount();
    }
内部类的注意点
  1. 内部类和外部类的名字不可以相同。
  2. 在编译外部类的时候,编译器会为每一个内部类生成单独的.class文件,.class文件名字为outclassname$innerclassname。
  3. 内部类可以使用外部类的类和实例变量。
  4. static 只能用于内部类,不能应用于外部类。
  5. 在内部类中不能申明static成员变量,除非内部类声明为static。
内部类生成对象方法
  1. 静态内部类
Test53.inner ti = new Test53.inner();
  1. 非静态内部类
    Test51 t = new  Test51();
    Test51.inner ti = t.new inner();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值