Android开发基础 -- 实体类 和 抽象类 详解
2016-12-06 19:51
591 查看
1. 实体类
在日常的Java项目开发中,entity(实体类)是必不可少的,它们一般都有很多的属性,并有相应的setter和getter方法。entity(实体类)的作用一般是和数据表做映射。所以快速写出规范的entity(实体类)是java开发中一项必不可少的技能。
大概的说,实体类就是:属性+get/set方法。
在项目中写实体类一般遵循下面的规范:
1、实体类的名字尽量和数据库的表的名字对应相同。
2、根据你的设计,定义一组你需要的私有属性。(如:private
int age;)
3、根据这些属性,创建它们的setter和getter方法。(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)例子:具体的细节都用注释标注了。
ps:
A. 关于构造器作用:利用构造器参数初始化对象的属性。
举个例子:
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类,其中还有一个映射文件。给定一个较复杂的实体关系(如一对一,一对多,多对多),应该熟练地写出实体类!!
[align=center]2. 抽象类
[/align]
简单的说,抽象类就是从一般类中抽取他们的共性封装成的类,所以抽象类的特点就像抽象的事物一样不是现实的不能被实例化。
[align=center]比如动物是抽象类(父类);狗,猫等就是动物的具体类(实例化),即子类。
【如,猫狗的共性:四条腿,两只耳朵 等】
[/align]
下面是关于抽象类的特点介绍:
1、 用abstract关键字来修饰一个类时,这个类叫做抽象类;用abstract来修饰一个方法时,该方法叫做抽象方法。(抽象方法一定定义在抽象类中)
2、 抽象方法没有方法主体,就是没有大括号,直接在小括号后面加分号。(如:public abstract void sayHello(); 就是抽象方法。)
3、抽象类中的方法要被使用,必须有子类覆写所有的抽象方法后,建立子类对象调用。
4、含有抽象方法的类必须被声明抽象类,抽象类必须被继承,抽象方法必须被重写。
5、抽象类不能被实例化(即不能用new创建对象),因为没有意义。
6、抽象方法只需声明,而不需实现。
7、 抽象类就是为了让子类继承的,它表示从一些具体类中抽象出来的类型。如果想要继承抽象类的话,必须要在子类中覆写抽象类中的全部抽象方法才行。
8、抽象类里面的方法只需声明,无需写方法体,方法体在子类中覆写时写入方法体就行了。
9、如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类;抽象类中即可有抽象方法也可以有非抽象方法。
10、抽象类中可以不定义抽象方法,这种作用仅仅用于不让该类创建对象。
下面是一个简单的抽象类例子:
注意:抽象类的继承者必须实现抽象方法,否则也必须被定义成抽象的,由下一个继承者实现。抽象类不能实例化对象。
又如,在Android开发中,经常会碰到自定义的 BaseActivity 、BaseFragment 等,这些就是大多数是抽象类;
我们在做Android应用的时候最基本的类当然是Activity了,我们一般的情况下要建立一个基类Activity然后让别的Activity来继承于它,但是我们可以使用一些小技巧来简便我们对这个BaseActivity的使用,如下:
那么我们来看下实现该抽象类:
其实就是一个非常简单的小知识点:
我们继承于一个类,让它成为抽象类,加上一些初始化的抽象方法,这样我们再继承于这个类的时候就必须去实现这些抽象方法,就不用我们去手动添加,这样也不会让我们丢失了一些操作,如初始化等,而且我们还把这些初始化的方法添加到了onCreate()方法中;
这样我们的子类只要继承于BaseActivity,有以下两点好处:
(1)肯定我们不用再去托运添加实现findViews()init()setLinsteners()这些初始化方法了,只需在这些子类中实行这些抽象方法即可;
(2)我们不用再在每个Activity中手动调用这三个方法,因为我们的BaseActivity已经为我们做好了封装;
OK,以后我们就这样搭建我们的BaseActivity吧;
*******************************************************************
网上有很多介绍BaseActivity的博文,多数是从应用的角度去描述的。
这里,我所介绍的BaseActivity不同,主要从框架搭建的角度去介绍BaseActivity的使用。
先看代码:
定义一个初始化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
[align=left]
[/align]
在日常的Java项目开发中,entity(实体类)是必不可少的,它们一般都有很多的属性,并有相应的setter和getter方法。entity(实体类)的作用一般是和数据表做映射。所以快速写出规范的entity(实体类)是java开发中一项必不可少的技能。
大概的说,实体类就是:属性+get/set方法。
在项目中写实体类一般遵循下面的规范:
1、实体类的名字尽量和数据库的表的名字对应相同。
2、根据你的设计,定义一组你需要的私有属性。(如:private
int age;)
3、根据这些属性,创建它们的setter和getter方法。(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 ea63 ) 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类,其中还有一个映射文件。给定一个较复杂的实体关系(如一对一,一对多,多对多),应该熟练地写出实体类!!
[align=center]2. 抽象类
[/align]
简单的说,抽象类就是从一般类中抽取他们的共性封装成的类,所以抽象类的特点就像抽象的事物一样不是现实的不能被实例化。
[align=center]比如动物是抽象类(父类);狗,猫等就是动物的具体类(实例化),即子类。
【如,猫狗的共性:四条腿,两只耳朵 等】
[/align]
下面是关于抽象类的特点介绍:
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
[align=left]
[/align]
相关文章推荐
- 【Android应用开发】 推送原理解析 极光推送使用详解 (零基础精通推送)
- Android自定义view基础详解及开发流程
- [置顶] android开发之java的一些基础知识详解,java编程语法,扎实自己的android基本功
- React Native 基础之从源代码编译详解-适合Android开发
- 【书摘001】android 底层开发技术实战详解 - 基础 - 进程管理的一些常用命令
- [置顶] Android开发之数据存储——SharedPreferences基础知识详解,饿补学会基本知识,开发者必会它的用法。
- Android基础之Jni开发流程详解(雷惊风)
- 【Android应用开发】 推送原理解析 极光推送使用详解 (零基础精通推送)
- android开发之java的一些基础知识详解,java编程语法,扎实自己的android基本功
- Android开发--JNI基础类型详解
- Android开发之旅:应用程序基础及组件(续)
- Android Map开发基础知识学习笔记
- 软件开发的基础知识—软件版本号详解
- Android开发之旅:应用程序基础及组件(续)
- Android系统原理及开发要点详解
- 实例详解快捷搭建Android手机开发平台
- Android UI开发专题(二) 之绘图基础
- Android系统原理及开发要点详解
- Android开发之旅:应用程序基础及组件
- 软件开发-Java基础与案例开发详解