Android开发基础 -- 实体类 和 抽象类 详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22078107/article/details/53492179
1. 实体类


       在日常的Java项目开发中,entity(实体类)是必不可少的,它们一般都有很多的属性,并有相应的setter和getter方法。entity(实体类)的作用一般是和数据表做映射。所以快速写出规范的entity(实体类)是java开发中一项必不可少的技能。

       大概的说,实体类就是:属性+get/set方法。

  在项目中写实体类一般遵循下面的规范:

               1、实体类的名字尽量和数据库的表的名字对应相同。

    2、根据你的设计,定义一组你需要的私有属性(如:private int age;)

    3、根据这些属性,创建它们的settergetter方法。(AndroidStudio 等集成开发软件可以自动生成。具体怎么生成请自行百度。)

    4、提供有参数的构造器(所有的参数)和无参数的构造器(如果你不手动写上构造方法。会默认帮你加上一个无参构造方法[不会显示出来])

                         关于构造器可以看看这几篇文章(在下面我也会大概说下):构造器的作用是什么?  Java构造器和方法的区别 

    5、重写父类中的eauals()方法和hashcode()方法。(如果需要涉及到两个对象之间的比较,这两个功能很重要。)

                                  关于重写这两个方法的原因可以看看这几篇文章: 重写equals和 hashCode方法 为什么重写equals的同时必须重写 hashcode为什么要重写equals

                                                                                                                            如何重写hashCode()和equals()方法1 如何重写equals和 hashCode方法2

    6、实体类应该实现Serializable接口(序列化)。(如:public class BaseEntity implements Serializable { }    )

                                   实体类为什么要序列化请参考这篇文章和这个贴: java实体类实现序列化的意义 (详细的解析) 和  Java序列化的意义(通俗易懂)

            7、还应该有个属性serialVersionUID(序列化版本号)。  (版本号为自动生成的,方法看下面网址)

                                   关于serialVersionUID作用介绍请看两篇文章: serialVersionUID作用   和 AndroidStudio自动生成SerialVersionUID方法
             

 下面是我写的一个实体类(entity)例子:具体的细节都用注释标注了。

/**一个学生的Java实体类*/
class Student implements Serializable{
    /**
     * 序列化版本号(自动生成,方法请看上面)
     */
    private static final long serialVersionUID = 88722423642445L;
    //定义的私有属性
    private int id;
    private String name;
    private int age;
    private double score;
    //无参数的构造器(如果不写系统会自动生成无参数的构造器,但不会显示出来)
    public Student(){
        
    }
    //有参数的构造器
    public Student(int id,String name,int age, double score){
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }
    //创建的setter和getter方法
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    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 double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    //由于id对于学生这个类是唯一可以标识的,所以重写了父类中的id的hashCode()和equals()方法。
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (id != other.id)
            return false;
        return true;
    }
    
}


ps:
A.  关于构造器作用
利用构造器参数初始化对象的属性
  举个例子:
public class Animal {
    private int legs;

    //无参构造器
    public Animal() {
        legs = 4; 
    }  
    //有参构造器
    public Animal(int legs) {
        this.legs = legs; 
    }    
    public void setLegs(int i) { legs = i; }
    public int getLegs(){return legs;}
}
创建Animal类的实例:Animal a=new Animal();   //调用无参构造器,将legs初始化为4;(即 a.legs=4)
                                         Animal a=new Animal(10);   //调用有参构造器,将legs初始化为10;(即 a.legs=10)

注释:构造器的名称必须与类名相同。修饰符:public、private、protected
构造器不是方法,没有返回值(连void也不能写)


B.  关于重写equals() 和 hashCode()方法的大致原因(具体介绍可以看看上面给出的那几个文章地址) :
默 认equals在比较两个对象时,是看他们是否指向同一个地址的。
但有时,我们希望两个对象只要是某些属性相同就认为他们的quals为true。比如:
Student s1 = new Student(1,"name1");
Student s2 = new Student(1,"name1");
如果不重写equals的话,他们是不相同的,所以我们要重些equals,判断只要他们的id和名字相同equals就为true,在一些集合里有时也这样用,集合里的contain也是用equals来比较;

另外:equals()相等的两个对象,hashcode()一定相等; 
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。



实体类 总结: 实体是就是Java中的O/R Mapping映射,即数据库中的一个表映射成对应的一个Java类,其中还有一个映射文件。给定一个较复杂的实体关系(如一对一,一对多,多对多),应该熟练地写出实体类!!






2. 抽象类


简单的说,抽象类就是从一般类中抽取他们的共性封装成的类所以抽象类的特点就像抽象的事物一样不是现实的不能被实例化

比如动物是抽象类(父类);等就是动物的具体类(实例化),即子类。
【如,猫狗的共性:四条腿,两只耳朵 等】

下面是关于抽象类的特点介绍:
1、 用abstract关键字来修饰一个类时,这个类叫做 抽象类;用abstract来修饰一个方法时,该方法叫做 抽象方法。(抽象方法一定定义在抽象类中)
2、 抽象方法没有方法主体,就是没有大括号,直接在小括号后面加分号。(如:public abstract void sayHello();  就是抽象方法。)
3、抽象类中的方法要被使用,必须有子类覆写所有的抽象方法后,建立子类对象调用。
4、含有抽象方法的类必须被声明抽象类,抽象类必须被继承,抽象方法必须被重写。
5、抽象类不能被实例化 (即不能用new创建对象),因为没有意义。
6、抽象方法只需声明,而不需实现。
7、 抽象类就是为了让子类继承的,它表示从一些具体类中抽象出来的类型。如果想要继承抽象类的话,必须要在子类中覆写抽象类中的全部抽象方法才行。
8、抽象类里面的方法只需声明,无需写方法体,方法体在子类中覆写时写入方法体就行了。
9、如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类;抽象类中即可有抽象方法也可以有非抽象方法。
10、抽象类中可以不定义抽象方法,这种作用仅仅用于不让该类创建对象。


下面是一个简单的抽象类例子:
/**
 * 声明抽象类;
 * 
 * (父类)
 **/
abstract class Animal{                   
    private String name;
    public Animal(String name){
        this.name = name;
    }

    public abstract void enjoy();        //声明抽象方法


}


/**
 * 继承抽象类;
 * 
 **/
class Dog extends Animal{

    private String forlorColor;
    public Dog(String name,String forlorColor){
        super(name);
        this.forlorColor = forlorColor;
    }

    // 实现抽象类里面的抽象方法       (即加些功能)
    protected void enjoy(){
        System.out.println("dog叫声~~~");
    }

}

注意:抽象类的继承者必须实现抽象方法,否则也必须被定义成抽象的,由下一个继承者实现。抽象类不能实例化对象。

又如,在Android开发中,经常会碰到自定义的 BaseActivity  、BaseFragment 等,这些就是大多数是抽象类;
我们在做Android应用的时候最基本的类当然是Activity了,我们一般的情况下要建立一个基类Activity然后让别的Activity来继承于它,但是我们可以使用一些小技巧来简便我们对这个BaseActivity的使用,如下:
/**
 *  继承activity的抽象类
 */
public abstract class BaseActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //子类继承该抽象类BaseActivity后就会按着这些抽象方法一步一步执行
        
        findViews();    //先 绑定控件
        init();       //然后 初始化视图
        setListeners();    //最后 设置监听器
    }
    
    //声明抽象方法
                         
    protected abstract void findViews();         
   
    protected abstract void init();           
   
    protected abstract void setListeners();    
}

那么我们来看下实现该抽象类:
/**
 * 继承抽象类,实现里面的抽象方法
 */
public class MainActivity extends BaseActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

// 实现下面 抽象类里面的抽象方法       (即加些功能等)

    @Override
    protected void findViews() {
    // TODO Auto-generated method stub
        //先在这里绑定控件
    }
    @Override
    protected void init() {
    // TODO Auto-generated method stub
        //然后初始化视图
    }
    @Override
    protected void setListeners() {
    // TODO Auto-generated method stub
        //最后 设置监听器
    }
}

其实就是一个非常简单的小知识点:
我们继承于一个类,让它成为抽象类,加上一些初始化的抽象方法这样我们再继承于这个类的时候就必须去实现这些抽象方法就不用我们去手动添加,这样也不会让我们丢失了一些操作,如初始化等,而且我们还把这些初始化的方法添加到了onCreate()方法中
这样我们的子类只要继承于BaseActivity,有以下两点好处:
(1)肯定我们不用再去托运添加实现findViews()init()setLinsteners()这些初始化方法了,只需在这些子类中实行这些抽象方法即可;
(2)我们不用再在每个Activity中手动调用这三个方法,因为我们的BaseActivity已经为我们做好了封装;

OK,以后我们就这样搭建我们的BaseActivity吧;


*******************************************************************

网上有很多介绍BaseActivity的博文,多数是从应用的角度去描述的。

这里,我所介绍的BaseActivity不同,主要从框架搭建的角度去介绍BaseActivity的使用

先看代码:

/**
 * 应用程序Activity的基类
 */
public abstract class BaseActivity extends Activity implements
        OnClickListener {

    private static final int ACTIVITY_RESUME = 0;
    private static final int ACTIVITY_STOP = 1;
    private static final int ACTIVITY_PAUSE = 2;
    private static final int ACTIVITY_DESTROY = 3;

    public int activityState;

    // 是否允许全屏
    private boolean mAllowFullScreen = true;

    //声明抽象方法
    public abstract void initWidget();
    public abstract void widgetClick(View v);

    public void setAllowFullScreen(boolean allowFullScreen) {
        this.mAllowFullScreen = allowFullScreen;
    }

   @Override
    public void onClick(View v) {
        widgetClick(v);
    }

    /***************************************************************************
     * 
     * 打印Activity生命周期
     * 
     ***************************************************************************/

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        AppLog.debug(this.getClass() + "---------onCreat ");

        // 竖屏锁定
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        if (mAllowFullScreen) {
            requestWindowFeature(Window.FEATURE_NO_TITLE); // 取消标题
        }

        AppManager.getAppManager().addActivity(this);

        initWidget();
    }

    @Override
    protected void onStart() {
        super.onStart();

        AppLog.state(this.getClass(), "---------onStart ");
    }

    @Override
    protected void onResume() {
        super.onResume();

        activityState = ACTIVITY_RESUME;
        AppLog.state(this.getClass(), "---------onResume ");
    }

    @Override
    protected void onStop() {
        super.onResume();
        activityState = ACTIVITY_STOP;
        AppLog.state(this.getClass(), "---------onStop ");
    }

    @Override
    protected void onPause() {
        super.onPause();

        activityState = ACTIVITY_PAUSE;
        AppLog.state(this.getClass(), "---------onPause ");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        AppLog.state(this.getClass(), "---------onRestart ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        activityState = ACTIVITY_DESTROY;
        AppLog.state(this.getClass(), "---------onDestroy ");
        AppManager.getAppManager().finishActivity(this);
    }

}

定义一个初始化Activity控件的抽象方法initWidget();

像findviewbyid()这类代码就可以写在这里,不会影响代码结构了。这里需要提一点的是:setContent()方法一定要写在initWidget()里,而不能再写到oncreate里面了,看代码可以知道,initwidget方法是存在于super()中的,而如果再写到oncreate里,就相当于先调用了findview再去调用setcontent,这样肯定会报空指针异常。

关于竖屏锁定,这个可以按需要添加,没什么说的。

还有一个要说的就是requestWindowFeature(Window.FEATURE_NO_TITLE); // 取消标题

对于这段代码,如果你要使用系统的ActionBar的时候,一点要记得调用setAllowFullScreen,设置为false,否则BaseActivity自动取消了ActionBar你又去使用,肯定也会出异常。

还有一点:Baseactivity已经实现了OnClickListener,所以子类无需再次实现,控件可以直接在initWidget里面setonclicklistener(this);然后在widgetClick(View v)中设置监听事件即可。

有关AppManager的内容我将放到下一篇《Android应用框架搭建》去讲解,这里大家可以先忽略。

有关生命周期的打印,我认为在调试阶段还是有必要的,毕竟看着每一个Activity的生命周期,如果出了问题马上就可以清楚的知道是哪里出了问题




其他关于BaseActivity的文章推荐:为你的Android应用定制属于你的BaseActivity,  Android App框架设计之编写基类BaseActivity





















猜你喜欢

转载自blog.csdn.net/qq_22078107/article/details/53492179