【有书共读】《疯狂JAVA讲义》读书笔记06
阅读了java疯狂讲义第六章的内容,我对面向对象思想有了更深入的了解,对java中的修饰符类似于static、final等有了一定的了解,还知道了接口的概念与作用,通过对这章的学习学到了很多东西。
理解类成员
类成员就是用static修饰的成员变量,方法,初始化块,内部类的统称。能通过对象访问这些类成员。即使对象是null 。类成员不能访问实例成员,因为类成员的作用域更大,可能类成员还存在,但是成员变量已经不存在了,所以不能够访问实例成员。
单例类
一个类始终只能创建一个实例,称为单例类。
如果不想让别的类轻易的创建该类的对象,就需要把类的构造函数设置成private,但是这个时候就需要有一个方法来创建一个对象,由于使用这个方法的时候还没有对象,因此需要给方法是static的。
同时。为了满足只能创建一个对象,则必须把已经创建的对象保存起来,每次创建对象之前都检查一下是否只有一个对象。由于存储对象的成员变量需要通过上面的static方法调用,因此需要设置为static。
package demo6;
public class Singleton {
//定义一个类变量用来保存创建出来的对象
private static Singleton instance;
private Singleton(){}
//定义一个能够返回对象的方法
public static Singleton getSingleton()
{
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Singleton s1=Singleton.getSingleton();
Singleton s2=Singleton.getSingleton();
System.out.print(s1==s2);
}
}
final修饰符
final修饰变量时候表示该变量一旦获得了初始值,就无法再改变。
final成员变量
类变量:在静态初始化块或者声明该变量时初始化
实例变量:在普通初始化块,或者声明该变量时候,或者构造器。如果已经在普通初始化块赋值,则不可以再在构造器中赋值。
注意⚠:普通方法不能访问final修饰的成员变量。
final修饰的成员变量必须程序员自己显示初始化,系统不会默认赋值。
final局部变量
因为系统不会给局部变量初始化,因此在用final修饰的局部变量不一定非由程序员显示初始化。
方法中的形参不能够在方法里面初始化,因为形参的初始化是在被调用的时候由实参传入的。
final修饰基本类型变量和引用类型变量的区别
final修饰基本类型变量,就不能更改值了。如果是引用类型,则只要不改变地址就行,里面的内容可以随意
package demo6;
import java.util.Arrays;
class Person1{
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person1() {}
public Person1(int age)
{
this.age=age;
}
}
public class FinalReferenceTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//可以无限的更改数组里面的内容,但是不能够更改数组的地址
final int[] iArr={3,4,5,6};
iArr[2]=19;
System.out.print(Arrays.toString(iArr));
Arrays.sort(iArr);
System.out.println(Arrays.toString(iArr));
//iArr=null;
Person1 p1=new Person1();
p1.setAge(7);
//这里竟然可以更改,,,,,不懂不懂
p1=null;
System.out.print(iArr);
}
}
可执行“宏替换”的final变量
变量满足三个条件,则变量相当于一个直接量
1. final修饰
2. 在定义的时候指定了初始值(只有在定义的时候赋值才有这种效果)
3. 值可以在编译的时候确定下来
final 方法
final方法不能够被重写。如果父类的方法不希望子类重写,只要加上final 就好。
但是父类的private 是不会被子类继承的,因此也不会有重写这个说法。因此如果父类的private方法被final了,子类仍然可以写一个一样的方法。
final类
不能有子类的类
不可变类
不可变类是创建该类的实例后,实例变量不能够更改。
创建自定义的不可变类方法:
1,类的成员变量用private和final修饰
2,提供带参数的构造函数,用于根据传入参数来初始化类的成员变量
3,该类仅有getter
4,重新定义equals()和hashcode()
package demo6;
public class Address {
private final String detail;
private final String postCode;
public Address()
{
this.detail="";
this.postCode="";
}
public Address(String detail,String postCode)
{
this.detail=detail;
this.postCode=postCode;
}
public String getDetail()
{
return detail;
}
public String getPostCode()
{
return postCode;
}
public boolean equals(Object obj)
{
if(obj==this)
{
return true;
}
if(obj!=null&&obj.getClass().equals(Address.class))
{
Address AddObj=(Address)obj;
if(AddObj.getDetail().equals(this.getDetail()))
{
return true;
}
}
return false;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
当创建不可变类的时候,如果成员变量里面有引用类型,则很可能创建出一个可变类,因为成员变量的内容可以更改。必须采用一些其他的方法,才能创建真正的不可变类。
缓存实例的不可变类
缓存实例的不可变类,是因为有的时候一个对象的某个成员被多次引用,为了节省开销,可以把它缓存起来。下边是把它缓存在数组里面,如果缓存里面已经有了,就直接返回实例,如果没有,就新建实例加进去。
package demo6;//这个类主要是弄一个数组,然后缓存string数据class CacheInnutale{
private static int MAX_SIZE;
private static CacheInnutale[] ***=new CacheInnutale[MAX_SIZE];
//pos为什么要是static
private static int pos=0;
private final String name;
public String getName() {
return name;
}
private CacheInnutale(String name)
{
this.name=name;
}
// 使用数组缓存已有的实例,并且记录缓存的位置
public static CacheInnutale valueOf(String name)
{
//遍历已经缓存的对象,如果有相同的,直接返回缓存的实例
for(int i=0;i<name.length();i++)
{
if(name!=null&&***[i].getName().equals(name))
{
return ***[i];
}
}
//如果缓存已经满了,则从头开始缓存
if(MAX_SIZE==pos)
{
***[0]=new CacheInnutale(name);
pos=1;
}
//缓存没满的话,把新建的对象缓存起来
else
{
***[pos++]=new CacheInnutale(name);
}
//因为是后➕,所以pos-1
return ***[pos-1];
}
}
public class CacheInnutaleTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
抽象类
抽象方法是只有方法的签名,没有方法的实现
抽象方法和抽象类
抽象方法和抽象类必须使用abstract修饰,有抽象方法的类一定是抽象类。
规则:
1. 抽象方法不能有方法体
2. 抽象类不能够被实例化
3. 抽象类的构造函数不能够用来创造实例,主要用于被子类调用
4. 含有抽象方法的类(包括直接定义了一个抽象方法;继承了一个抽象父类,但是没有完全实例化父类包含的抽象类;或是实现了一个接口,但是没有完全实例化接口包含的抽象方法)
public class Triangle extends Shape{
//定义三角形的三边
private double a;
private double b;
private double c;
public Triangle(String color,double a,double b,double c)
{
super(color);
this.sideSides(a,b,c);
}
public void sideSides(double a,double b,double c)
{
if(a+b<=c||a+c<=b||c+b<=a)
{
System.out.print("两边之和必须大于第三边");
return ;
}
this.a=a;
this.b=b;
this.c=c;
}
//重写计算周长的方法
public double calPerimeter()
{
return a+b+c;
}
public String getType()
{
return "三角形";
}
public static void main (String[] args)
{
//如果不用抽象类的话,s1是不能够直接调用gettype方法的。
Shape s1=new Triangle("yello", 3, 4,5);
System.out.println(s1.getType());
System.out.print(s1.calPerimeter());
}
}
abstract与final不能同时出现:abstract类表示只能被继承,但是final类不能被继承。 abstract和static一般不能同时修饰方法:static修饰的方法表示属于类的,可以通过类来访问。但是如果同时也是abstract的话,则没有方法体。这就没办法调用。(内部类除外) abstract和private不能同时修饰方法:private修饰的方法是不会被继承的。但是abstract需要继承。
抽象类的作用
作为子类的模版。
java8改进的接口
将抽象类“抽象”到极致,只包含抽象方法。就是接口。
接口的概念
接口定义的是多个类共同的公共行为规范,接口里通常是定义一组公共方法。
接口不提供任何实现,体现的是实现和规范相分离的设计哲学。
java8中接口的定义
关键词:interface
修饰符:public 或者省略,省略是默认default
一个接口可以继承多个接口
由于接口定义的是一种规范,因此接口没有构造器和初始化块,接口可以包含成员变量(静态常量),静态方法和抽象方法以及默认方法。都必须是public
1. 静态常量:无论是否有修饰符,都是public static final的,需要在定义的时候指定默认值。可以跨包访问,但是因为是final,不能修改值。
2. 接口里面的普通方法只能是public的抽象abstract方法
3. 在接口定义默认方法,需要使用default修饰(默认都是public修饰,不能static修饰)
4. 在接口定义类方法,需要使用static(默认都是public ,不能用default修饰)
5. java里面最多定义一个public的接口,如果有public的接口,则主文件名和接口名相同
接口的继承
支持多继承,以逗号分格
使用接口
implements实现多个接口。如果一个类继承了一个接口,就必须把里面的抽象方法都实现,否则就必须定义成抽象类。
实现接口的方法时必须使用public
模拟多继承:接口名引用变量名=new 类(初始化参数),类就可以访问接口的方法以及自己的方法。类的方法就变的很多。
package demo6;//定义一个product接口interface Product{
int getProductTime();
}public class Printer implements Product , Output{
private String[] printData=new String[MAX_CACHE_LINE];
//记录当前需打印的作业数
private int dataNum=0;
public void out()
{
//只要还有作业就继续打印
while(dataNum>0)
{
System.out.println(printData[0]);
System.arraycopy(printData, 1, printData, 0, --dataNum);
}
}
public void getData(String msg)
{
if(dataNum>=MAX_CACHE_LINE)
{
System.out.println("输出队列已经满了。添加失败");
}else {
printData[dataNum++]=msg;
}
}
public int getProductTime()
{
return 45;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建一个printer对象,当成output使用
Output o=new Printer();
o.getData("疯狂jav");
o.getData("疯狂jaba讲义");
o.out();
o.getData("疯狂安卓讲义");
o.getData("疯狂安卓");
o.out();
}
}
接口和抽象类
接口:体现一种规范,对于接口的实现者,接口定义了必须实现那些服务;对于接口的调用者,规定了调用者可以调用哪些方法。
抽象类:体现一种模版的设计,他是没有设计完的一个类,需要子类补充将它完成。