JavaSe ——3、面向对象

来源:互联网 发布:淘宝苹果4s外壳多少钱 编辑:程序博客网 时间:2024/06/06 14:08

this关键字:

  • 在构造器中代表正在实例化的对象,在方法中代表正在调用该方法的对象。
  • 因为代表的是对象,不可与static一起用,即static(静态成员)不可访问非静态成员。

类内元素:属性、方法、构造函数、初始化块。

方法:

  • 方法的传参:都是值传递,不存在引用传递。(形参是基本类型无法改变参数本身的值,引用类型则传入的值是堆地址值,可以改变参数本身的值)
  • 方法重载:同一个类,同一个函数名,不同参数(个数or类型)

类的变量(属性)类型:

  • 成员变量:类变量(static)和实例变量。
  • 局部变量:形参、方法中、代码块中。
  • 一个类不能有两个同名的成员变量,一个方法不能有两个同名的局部变量(一个在方法中一个在代码块中也不行)
  • 局部变量和成员变量可同名,局部变量会覆盖成员变量,要用成员变量则用this.来引用。
  • 静态成员变量在类初始化时会分配内存空间并制定初值,普通成员变量在创建对象时分配内存并制定初值。
  • 局部变量在其所在的方法栈内存中,为局部变量赋值时才分配内存。

构造器:

  • 如果不写构造器,会自动提供,在创建对象时会初始化,基本类型的属性设为0,引用类型的属性设为null。
public Class People{    private String name;    private String age;    public People(String name,String age){    this.name = name;    this.age = age;    }    public void main(String[] args){        People p1 = new People("like",25);      }}

这么写后就不能通过new People();创建对象。

  • 重载构造器:
public People(){}public People(String name){    this.name = name;} 

初始化块

  • 普通初始化块:先于构造函数执行,可以把多个构造函数共有的部分放在普通初始化块中,提高代码复用。创建对象时,先执行Object的初始化块,然后父类初始化块,然后自己的。

  • 静态初始化块:类加载时执行,也会先调用Object的静态初始化块,然后父类的,然后自己的。

包装类

toString();重写,可以描述对象信息。

==和equals:

  • ==:如果基本类型,数值一样即为true,类型不一样也可以,如果引用类型,则必须引用同一个对象。且不可比较两个没有继承关系的对象,否则编译报错。
  • equals方法是Object类的方法,作用和==一样,但是String类重写了equals方法,所以比较字符串的内容是否相等必须用equals方法。

String s1=new String(“abc”);和String s2=”abc”;

  • String s2=”abc”;执行时,JVM在字符串常量池查看是否纯在”abc”这个常量,存在即之间使s2指向这个常量,不存在则先在常量池创建”abc”,然后s2指向。所以创建了0或1个对象。

  • String s1=new String(“abc”);同样也是JVM在字符串常量池查看是否纯在”abc”这个常量,如果不存在,则先在常量池创建”abc”,然后在堆内存创建String类的对象,并把常量池的”abc” copy过来(有待考证)。所以创建了1个或2个对象。

  • 常量池中不能有重复的字符串。

单例类:一个类只能创建一个实例。

  • 创建步骤

1、需要通过private修饰构造器,从而不能在类外new对象。

2、类内提供生成实例的方法,因为在类外调用,所以需要用public修饰该方法,因为在生成实例前无实例,所以只能通过类来调用,所以修饰该方法同时要用static,且需要在方法中判断该类是否存在实例化对象。

3、通过成员变量缓存已经构建好的实例,该成员变量需要被生成实例的static方法调用,因此也必须为static。

代码:

Class Singleton{    private static Singleton instance;    pivate Singleton(){}    public static Singleton getInstance(){        if(instance == null){        instance new Singleton();        return instance;    }    return instance;}public Class Test{    public static void main(String[] args{    {        Singleton t1 = Singleton.getInstance();        Singleton t2 = Singleton.getInstance();        System.out.println(t1==t2); //true    }}
  • 单例模型的应用:

一般在两种场景下会考虑使用单例(Singleton)模式:

1、产生某对象会消耗过多的资源,为避免频繁地创建与销毁对象对资源的浪费。如: 对数据库的操作、访问IO、线程池(threadpool)、网络请求等。

2、某种类型的对象应该有且只有一个。如果制造出多个这样的实例,可能导致:程序行为异常、资源使用过量、结果不一致等问题。如果多人能同时操作一个文件,又不进行版本管理,必然会有的修改被覆盖,所以:
一个系统只能有:一个窗口管理器或文件系统,计时工具或ID(序号)生成器,缓存(cache),处理偏好设置和注册表(registry)的对象,日志对象。

static修饰符

  • 静态成员不能访问非静态成员。

final修饰符

  • 修饰类、变量、方法,一旦赋值就不可变。

  • 如果final修饰的成员变量没有在定义时、初始化块中、构造器中赋值,则系统会默认分配0、false或null,final修饰的成员变量必须显式赋值。

  • final修饰的局部变量可在定义时赋值或在后面赋值,修饰形参不可赋值,在调用时才赋值。

  • final修饰基本变量,其值不可变,修饰引用变量,因为存的是地址,所以引用对象中的值可变,引用的对象不可变。

  • final修饰的转变为常量:定义时确定初始值,编译时即可确定值,则为常量,编译时遇到该变量后会被替换为常量。

  • final修饰的方法不可被重写(比如父类的方法不希望被重写,可用final修饰),但可重载。

  • final修饰的类不可以有子类。(java.lang.Math)

  • 不可变类(类创建了实例后,实例的属性不可改变)

创建不可变类:
1、用private final修饰属性。
2、提供带参构造器。(new String(“abc”);)
3、不提供setter方法。
4、重写hashcode和equals方法(可选)

比如String和包装类就是不可变类。且String重写了hashcode和equals,两个一样的String的hashcode相等。

如果类中private final修饰的是引用类型,在带参构造器时,new一个引用类返回给成员变量,保证不可变性。

缓存

  • 缓存不可变类的实例(由于实例不可变,重复创建无意义,加大开销,某个对象需要频繁重复使用,则缓存)
  • 写个缓存:
Class Cache{    private static int MAX_SIZE = 10;    private  static Cache[] cache = new Cache[MAX_SIZE];    private static int pos = 0;    private final String name;    private Cache(String name){        this.name = name;    }    private String getName(){            return name;        }    public static Cache valueof(String name){            for(int i=0;i<MAX_SIZE;i++){                if(cache[i] !=null && cache[i].getName().equals(name)){                    return cache[i];                }            }            if(pos == MAX_SIZE){                cache[0] = new Cache(name);                pos = 1;            }            else{                cache[pos++] = new Cache(name);                }                return cache[pos-1];        }    }
  • 缓存不可变类的应用:

    JDK1.5后 Integer类新增了一个参数,为int类型的静态工厂方法valueOf(int i),它的处理流程如下:

    if(在实例缓存中存在取值为i的实例)
    直接返回这个实例
    else{
    用new语句创建一个取值为i的Integer实例
    把这个实例存放在实例缓存中
    }

    Integer a=new Integer(10); \\创建一个实例Integer c=Integer.valueOf(10);\\创建一个实例,并放在缓存中。Integer d= Integer.valueOf(10);\\直接返回缓存中的实例,所以c==d为true

内部类:

  • 一个类放在另一个类的内部定义,包含内部类的类叫外部类。

  • 更好的封装:内部类隐藏在外部类中,不允许包内其他类访问。

  • 内部类作为外部类的成员,因此可以访问外部类的私有(private)数据,但外部类无法访问内部类的成员。

  • 仅需要使用一次的类适合用匿名内部类。

  • 内部类作为外部类的成员,分为静态内部类(static修饰)和非静态内部类。

  • 内部类也可以用public、private和protected修饰。

  • 一个含有内部类的类,编译后为两个文件:外部类.class和外部类$内部类.class。

  • 如果外部类的成员变量、内部类的成员变量和内部类的某方法有同名变量,可以用this.变量名和外部类.this.变量名区分。

  • 外部类访问非静态内部类的成员时,需要通过new内部类对象访问,不可直接访问。

  • 非静态内部类不可以有静态的成员。

  • 静态内部类:static修饰的内部类,内部类中可以有静态成员和非静态成员,但只能访问外部内的静态成员。

  • 接口中可以定义静态内部类,用public static修饰。

  • 外部类内部使用内部类,new内部类对象。

  • 外部类以外定义非静态内部类,内部类不可用private修饰,Out.In in = new Out().new In();

  • 外部类以外定义静态内部类:外部类.内部类 in = new 外部类.内部类。

  • 内部类的使用技巧:
    http://blog.csdn.net/hivon/article/details/606312

垃圾回收(GC)

  • 只回收堆内存中的对象,垃圾回收任何对象前会调用finalize()方法,可能让对象复活。
  • 对象在内存中的状态:
    • 可达:一个以上的引用。
    • 可恢复:没有引用,但还未执行finalize()方法。
    • 不可达:无任何引用,执行完finalize()方法后也没复活。
  • 强制垃圾回收:
    • System.gc()
    • Runtime.getRuntime().gc()
  • 四种对象引用:
    • 强引用
    • 软引用
    • 弱引用
    • 虚引用