java进阶- 第五天

面向对象下

1.1 java8的增强那包装类

为了解决8种基本数据类型的变量不能单程Object类型的变量使用的问题,java提供了包装类的概念,为8中基本数据类型分别定义了相应的引用类型,称之为基本数据类型的包装了类。(Objcet类是所有类的父类)

public class AutoBoxingUnboxing
{
   public static void main(String[] args)
   {
     //直接把一个基本类型变量付给Integer对象
     Integer inObj=5;
     //直接把bloolean类型变量赋给一个Object类型的变量
     Object boolObj=true;
     //直接把一盒Integer对象赋给int类型变量
     int it=inObj;
     if(boolObj instanceof Boolean) // instance它的作用是判断其左边对象是否为其右边类的实例
     {
       //先把object对象强制类型转换为Boolean类型,再赋给boolean变量
       boolean b=(Boolean)boolObj;
       System.out.println(b);
     }
     
   }
}

** java7为所有的包装类都提供了一个静态的compare,用来比较两个基本类型值得大小
例如 Boolean.compare(true,false)

1.2处理对象

打印对象和toString方法

==和equals方法

重要:==只比较数值 当是两个引用类型不同的对象比较时,返回false
很多时候程序判断两个引用变量是否相等时,并不严格要求两个引用变量指向同一个对象。那就可以用Stiing对象的equals方法来判断

//String中重写Object类的equals方法的源码
public boolean equals(Object anObject)
{
    if(this==anObject)
    {
        return true;   //如果是同一个实例 那么return true
    }
    if(anObject instanceof String)//看是否是tring的子例
    {
        String anotherString=(String)anObject;
        int n=value.length;
        if(n==anotherString.value.length)  //如果长度相等
        {
          //分别放入数组中就行比较
           char v1[]=value;
           char v2[]=abotherString.value;
           int i=0;
           while(n-- !=0)
           {
               if(v[i]!=v2[i])
                 return false;
                i++;
           }
           return true;
        }
    }
    return false;
}

1.3类成员

单例模式例子

class singleton
{
   //使用一个类变量来缓存曾经创建的实例
   private static Singleton instance;
   //对构造器使用private修饰,隐藏该构造器
   private Singleton(){}
   //提供一个静态方法,用于返回Singleton实例
   //该方法可以加入自定义控制,保证只产生一个Singleton对象
   public static Singleton getInstance()
   {
       //如果instance为null,则表明还不曾创建Singleton对象
       //如果instance不为null,则表明已经创建了Singleton对象
       //将不会重新创建新的实例
       if(instance==null)
       {
          //创建一个Singleton对象,并将其缓存起来
          instance=new Singleton();
       }
       return instance;
   }
}
public class SingletonTest
{
    public static void main(String[] args)
    {
       //创建Singleton对象不能通过构造器
       //只能通过getInstance方法来得到实例
       Singleton s1=Singleton.getInstance();
       Singleton s2=Singleton.getInstance();
       System.out.println(s1==s2);  //输出true,因为只有一个实例被创建
    }
}

1.4final修饰符

final关键字用于修饰类、变量个方法,一旦被修饰将不能改变
** final修饰的成员变量必须由程序员显式的指定初始值

1.4.1 final成员变量
public class FinalVariableTest
{
    //定义成员变量时指定默认值,合法
    final int a=6;
    //下面变量将在构造器或初始化块中分配初始值
    final String str;
    final int c;
    final static double d;
    //既没有指定默认值,也没有再初始化快,构造器中指定初始值
    //下面定义的ch实例变量是不合法的
    //final char ch;
    //初始化块,可对没有指定默认值的实例变量指定初始值
    {
        //在初始化块中为实例变量指定初始值,合法
        str="Hello";
        //定义a实例变量时已经指定了默认值
        //不能为a重新赋值,因此下面赋值语句非法
        //a=9;
    }
    //静态初始化块,可对没有指定默认值的类变量指定初始值
    static
    {
        d=5.6;
    }
    //构造器,可对既没有指定默认值,又没有在初始化块中
    //指定初始值的实例变量指定初始值
    public FinalVariableTest()
    {
        //如果已经在初始化块中已经对str指定的初始值
        //那么在构造器中不能对final变量重新复制,
        //str=“java”   语句非法
        c=5;
    }
    public void changeFinal()
    {
        //普通方法不能为final修饰的成员变量赋值
      //d=1.2;
      //不能在普通方法中为final成员变量指定初始值
      //ch=“a”;
    }
}

**与普通成员变量不同的是,final成员变量必须由程序员显式初始化,系统不会对final成员进行隐式初始化

1.4.2 final修饰局部变量,

可以定义时指定默认值,也可以不指定默认值,没有指定默认值的可以在后面代码中赋值,但只能一次,不能重新赋值

1.4.3 final修饰的基本类型变量和引用类型变量区别

当修饰基本类型变量时,不能对变量重新赋值,引用类型变量只要保证引用的地址不改变就行。

1.4.4 可执行“宏替换”的final变量

**final修饰符的一个重要用途就是定义“宏变量”。当定义final变量时就为该变量指定了初始值,而且该初始值可以在编译时就确定下来,那么这个final变量本质上就是一个“宏变量”,编译器会把程序中所有用到该变量的地方直接替换成该变量的值。

注意:对于final实例变量而言,只有在定义该变量时指定初始值才会有“宏变量”的效果。

1.4.5 final方法

final修饰的方法不可被重写,不会希望子类重写父类的某个方法,则可以使用final修饰该方法

1.4.6 final类

final修饰的类不可以有子类。

1.1.7 不可变类、

不可变类的意思是创建该类的实例后,该类的实例是不可改变的。java提供的8个包装类和java.lang.String类都是不可变类

创建自定义的不可变类,遵循如下规则:
1 使用private和final修饰符来修饰该类的成员变量
2提供带参数的构造器,用于根据传入参数来初始化类里的成员变量
3 仅为该类的成员变量提供getter方法,因为普通方法无法修改final修饰的成员变量。
4 如果有必要,冲洗人Object类的hashCode()和equals()方法

注意:当使用final修饰引用变量时,仅仅表示引用变量不能被赋值,但是引用变量所指向的对象依然可改变。这就会产生问题,当创建不可变类时,如果包含的成员变量的类型是可变的,那么其对象的成员变量的值依然可以改变,那么这个不可变类就是失败的。

1.4.8 缓存实例的不可变

如果程序经常使用相同的不可变类,那么应该考虑缓存这种不可变类,用于节省开销。
缓存的实现方式很多,现在提供一个数组作为缓存池,从而实现一个缓存实例的不可变类

class CachImmutale
{
    private static int MAX_SIZE=10;
    //使用数组来缓存已有的实例
    private static CacheImmutale[] cache=new CacheImmutale[MAX_SIZE];
    //记录缓存实例在缓存中的位置,cache[pos-1]是新缓存的实例
    private static int pos =0;
    private final String name;
    //构造函数
    private CachImmutale(String name)
    {
        this.name=name;
    }
    public String getName()
    {
       return name;
    }
    public static CachImmutale valueOf(String name)
    {
        //遍历已缓存的对象
        for(int i=0;i<MAX_SIZE;i++)
        {
          if(cache[i]!=null)&&cach[i].getName().equals(name))
          {
             return cache[i];
          }
        }
        //如果缓存池已经满
        if(pos==MAX_SIZE)
        {
            //把缓存的第一个对象覆盖,
            cache[0]=new CacheImmutale(name);
            //吧pos设为1
            pos=1;        
         }
         else
        {
        //把新创建的对象缓存起来,pos加1
        cache[pos++]=new CacheImmutale(name);
         }
    return cache[pos-1];
    }
    public boolean equals(Object obj)
    {
        if(this==obj)
        {
            return true;
        }
        if(obj!=null&&obj.getClass()==CacheImmutale.class)
        {
            CacheUmmulate ci =(CacheImmutale)obj;
            return name.equals(ci.getName());
        }
        return false;
    }
    public int hashCode()
    {
       return name.hashCode();
    }
    
    
}
public class CacheImmutaleTest
{
   public static void main(String[] args)
   {
       CacheImmulate c1=CacheImmutale.valueOf("hello");
       CacheImmulate c2=CacheImmutale.valueOf("hello");
       System.out.print(c1==c2)    //true
       //c1和c2是同一个对象
   }
}

6.5 抽象类

注意:有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法

6.5.1 抽象方法和抽象类

两者规则如下:
1 抽象类必须使用abstract修饰符来修饰
2 抽象类不能被实例化,只能被继承
3 抽象类中的构造器不能用于创建实例,主要用于被其子类调用

同时注意 abstract就是要让子类继承的 不能用private修饰

6.5.2 抽象类的作用

抽象类属于那种从子类抽象出来的父类,子类以抽象类为模板可以避免子类设计的随意性。

6.6 java8 改进的接口

功能类似于抽象类 但是是更彻底的抽象,java8对接口进行了改进,允许在接口中定义默认方法,默认方法可以提供方法实现。
接口的目的就是要让规范和实现分离 而接口就是这个规范。接口里通常定义的是一组公用方法。

注意:接口只能定义接口,不能定义类,接口里方法只能是抽象方法,类方法或默认方法。只能用public修饰符

同时注意:不管是否使用public static final修饰符,接口里的成员变量总是使用这三个修饰符来修饰。

系统将自动的为普通方法增加abstract修饰符。接口里的普通方法不能有方法实现,但是类方法,默认方法都必须有方法实现。

默认方法必须使用default修饰,类方法必须使用static修饰

从某个角度来看,接口被当成一个特殊的类,因此一个java源文件最多只能有一public接口,如果一个源文件里定义了一个public 接口,则该源文件的主文件名必须与接口名相同。

接口支持多继承,也就是一个类可以实现多喝接口

一个类实现了一个接口就要实现接口里全部的抽象方法。

6.6.6面向接口编程

6.7内部类

把一个类放在另一个类的内部定义,这个定义在内部的类称为内部类
好处:1 封装性更好
2 内部类成员可以直接访问外部类私有数据
3 匿名内部类适合用于创建那些仅需要一次使用的类
4 非静态内部类不能拥有静态成员

6.7.1 非静态内部类

没有static修饰的就是非静态内部类
注意:非静态内部类的成员可以访问外部类的private成员,但是反过来不成立。非静态内部类的成员只在非静态内部类范围内是可知的,并不能被外部类直接使用。

静态成员不能访问非静态成员,因此main函数不能直接访问内部类,会出错

public class StaticTest
{
    //定义了一盒非静态内部类
    private class In{}
    public static void main(String[] args)
    {
        new In();  // 报错,因为静态成员不能访问非静态方法
    }
}
6.7.2 静态内部类

使用static修饰的内部类,就是静态内部类

static不可修饰外部类(因为外部类上一级是包),只能修饰内部类

public class StaticInnerClassTest
{
    private int prop1=5;
    private static int prop2=9;
    //静态内部类里可以包含静态成员
    static class StaticInnerClass
    {
        private static int age;
        publuc void accessOutprop()
        {
        //代码错误 静态内部类无法访问外部类的实例变量
             System.out.print(prop1)
           //  代码正常,
             System.out.print(prop2)
             
        }
    }
}

注意:因为使用静态内部类比使用非静态内部类要简单很多,因此程序员使用内部类的时候,应优先考虑使用静态内部类

6.7.4 局部内部类

把一个内部类放在方法里定义,就是局部内部类,局部内部类只在方法里有效

6.7.5 java8改进的匿名内部类

匿名内部类适合那种只需要异地使用的类,创建匿名内部类时会立刻创建一盒该类的实例,这个类定义立刻消失,匿名内部类不能重复使用

语法

new 实现接口() | 父类构造器(实参列表)
{
    
}

从代码可以看出匿名内部类必须继承一个父类,或者实现一个接口。

最常用的匿名内部类的方式是需要创建某个接口类型的对象

Interface Priduct
{
    public double getProce();
    public String getName();
}
public class AnonymoueTest
{
    public void test(Product p)
    {
        System.out.println("购买了一个"+p.getName()+"
        ,花掉了"+p.getPrice());
    }
    public static void main(String[] args)
    {
        AnnonyTest ta=new AnonymousTest();
        //调用test()方法时,需要传入一个Product参数
        //此处传入其匿名实现类的实例
        ta.test(new Product()
        {
            public double getPrice()
            {
               return 568.5;
            }
            public String getName()
            {
               return "施维赫夫";
            }
        }
        );
    }
}

上面代码中Product只是一个接口,无法直接创建对象。如果Product接口实现类需要重复使用,则应将该实现类定义成一个独立类,如果这个Product接口实现类只需使用一次,则可使用上面程序的方式,定义一个匿名内部类

java8更改如下:如果局部变量被匿名内部类访问,那么该局部变量相当于自己动用了final修饰

java8新增的Lamba表达式

Lamba表达式支持将代码块作为方法参数,Lamba表达式允许使用更简洁的代码创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值