編輯:關於Android編程
說是原創,但本系列實際上是編程思想,Effective Java,深入理解JVM,以及一些大神
博客的筆記,主要內容就是一些理論問題的實踐,一些實踐問題容易踩的坑,一些坑的
解決方案 等,純Java系列有十幾篇,後面還會有安卓系列,相關的代碼鏈接:純java代
碼– https://github.com/cowthan/JavaAyo,安卓demo代碼–
https://github.com/cowthan/AyoWeibo,後續代碼也會重整一下,以配合本系列的
內容。
本系列的部分章節和大部分的格式問題,之後會由Mr.LongFace同學負責,作為IT
行業的新生代,我們倆都是特別謙虛的人,所以歡迎各位盡情批評指正。
後續內容:
5 對象池:對象太重
6 Flyweight享元模式:對象太多
7 備忘錄模式:狀態保存,對象快照
8 原型模式:是啥來著
9 對象clone
10 序列化
11 四種引用
12 內存模型和垃圾回收
13 對象緩存
//常規模式
public static class Boolean{
//靜態工廠方法
public static Boolean valueOf(boolean b){
return new Boolean(b);
}
private boolean v;
private Boolean(boolean b){
v = b;
}
}
//高級模式:限制對象的數目,比如單例,此處的例子是:Boolean基本就只能對應兩個值
public static class Boolean{
//預定義的兩個對象,某種意義上算是緩存,使用時可以省去創建對象的過程
public static final Boolean True = new Boolean(true);
public static final Boolean False = new Boolean(false);
//靜態工廠方法
public static Boolean valueOf(boolean b){
return b ? True : False;
}
private boolean v;
private Boolean(boolean b){
v = b;
}
}
靜態工廠方法的好處是:
優勢1
:方法有名字,構造器沒有,如BigInteger.probablePrime方法,這就是靜態工廠,表示BitInteger(int, int, Random)返回的很可能是素數 對於多種參數形式的構造器,可以各自對應一個靜態工廠,並給不同名字,還是參考probablePrime 優勢2
:可以預先構建對象,如Boolean.TRUE和FALSE,類似Flyweight模式 可以管理對象個數,如單例模式,也可以仿枚舉,業務邏輯上的相等的值,只給一個對象 優勢3
:可以返回任意子類型的對象,返回的父類或者接口引用,具體實現類甚至可以對外隱藏,參考Java Collections Framework中集合接口的32個便利實現 (1)Collections裡有unmodified, empty, checked, synchronized各8個方法,對應8種不同的集合類型 這8種集合類型就是:Collection, List, Map, SortedMap, NavigableMap, Set, SortedSet, NavigableSet,注意這是接口類型,對外的 返回的實際類型是什麼呢,都是以private static class的形式實現的,並未對外公開,所以可以jdk隨時修改,提升性能或修改實現 (2)EnumSet:其靜態工廠方法會根據底層枚舉類型大小,返回RegalarEnumSet對象或者JumboEnumSet對象,而且這對外部用戶是隱藏的 (3)這裡又能引出服務器提供者的概念 優勢4
:簡化Map
這是從靜態工廠好處3裡引出來的,對外提供一個接口,客戶端依賴於此接口實例,但並不關心具體實現
三大組件:以JDBC為例服務接口
:Service Interface,提供者實現,如Connection 提供者注冊API
:Provider Registreation API,用來注冊實現,讓客戶端訪問,如DriverManager.registerDriver() 服務訪問API
:Service Access API,客戶端用來獲取服務實例,這裡就是靈活的靜態工廠,如DriverManager.getConnection() 服務提供者接口
,Service Provider Interface,可選,用來創建服務實例,如果沒有這個,就得按照類名注冊,並通過反射實例化,如Driver就是這個角色
/**
* ================服務接口:Service Interface==================
* 一個對外提供服務的接口,並且不同情況,會產生不同的Service對象,
* 即通過Service的不同實現,對外提供不同的服務
*
*/
public interface Service {
void doService();
}
/**
* ================服務提供者接口==================
* 用來生成Service對象,注意,如果不使用Provider,則注冊到Services的就得是Service實現類的Class對象,
* newInstance也只能通過反射來了
* 問題就是Provider實現類應該有幾個
*
*/
public interface Provider {
Service newService();
}
public class Services {
private Services(){}
//================提供者注冊API==================//
//這裡要麼注冊provider對象,要麼注冊Service實現類的Class,你選吧
private static final Map providers = new ConcurrentHashMap<>();
public static final String DEFAULT_PROVIDER_NAME = "";
public static void registerDefaultProvider(Provider p){
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
public static void registerProvider(String defaultProviderName, Provider p) {
providers.put(defaultProviderName, p);
}
//================服務訪問API==================//
public static Service newInstance(){
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider p = providers.get(name);
if(p == null){
throw new IllegalArgumentException("No provider registered with name + " + name);
}
return p.newService();
}
}
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
public static class Builder{
//必填的參數,無默認值
private final int servingSize;
private final int servings;
//選填的參數,有默認值
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings){
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val){ calories = val; return this; }
public Builder fat(int val){ fat = val; return this; }
public Builder carbohydrate(int val){ carbohydrate = val; return this;}
public Builder sodium(int val){ sodium = val; return this; }
public NutritionFacts build(){
return new NutritionFacts(this);
}
}
}
public static void main(String[] args) {
NutritionFacts cocacola = new NutritionFacts.Builder(240, 8)
.calories(100)
.sodium(35)
.carbohydrate(27)
.build();
}
public interface Builder {
public T build();
}
package com.cowthan.object_management;
public class NutritionFacts2 {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public NutritionFacts2(MyBuilder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
public static class MyBuilder implements Builder{
//必填的參數,無默認值
private final int servingSize;
private final int servings;
//選填的參數,有默認值
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public MyBuilder(int servingSize, int servings){
this.servingSize = servingSize;
this.servings = servings;
}
public MyBuilder calories(int val){ calories = val; return this; }
public MyBuilder fat(int val){ fat = val; return this; }
public MyBuilder carbohydrate(int val){ carbohydrate = val; return this;}
public MyBuilder sodium(int val){ sodium = val; return this; }
public NutritionFacts2 build(){
return new NutritionFacts2(this);
}
}
public static void main(String[] args) {
Builder builder = new NutritionFacts2.MyBuilder(240, 8)
.calories(100)
.sodium(35)
.carbohydrate(27);
NutritionFacts2 cocacola = builder.build();
}
}
/*
這裡的Builder builder對象,可以傳給任意的抽象工廠方法
*/
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton(){}
private Object readResolve(){ return INSTANCE; }
public void provideService(){
}
}
//訪問
Singleton.INSTANCE.provideService();
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){ return INSTANCE; }
private Object readResolve(){ return INSTANCE; }
public void provideService(){
}
}
//訪問
Singleton.getInstance().provideService();
延遲加載
volatile的使用
public class Singleton{
private volatile static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
這裡的說法是:
SingletonHolder作為一個內部類,會在訪問時被加載,所以這裡實現了延遲加載,並且內部類可以從語言層面上防止多線程的問題,比雙重鎖模式優雅的多。
public class Singleton{
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
按照Effective Java書裡說法,這個方法雖然沒流行起來,但這個是最佳方式,第2版15頁
//直接就能防止反射,防止序列化時生成新類
//是否延遲加載不知道
public enum Singleton {
INSTANCE;
public void provideService(){
}
}
public class Singleton {
private Singleton(){}
public void doSth(){
System.out.println("做點什麼");
}
}
public class SingletonFactory {
private static Singleton singleton;
//===只實例化一次,使用暴力反射
static{
try {
Class cls = Class.forName(Singleton.class.getName());
Constructor cons = cls.getDeclaredConstructor();
cons.setAccessible(true);
singleton = (Singleton) cons.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Singleton getSingleton(){
return singleton;
}
/**
* 擴展:一個項目可以有一個單例構造器,負責生成所有單例對象,只需要傳入類型,
* 但是需要事先知道有幾個單例類型
*/
}
這節的內容感覺有點不對勁,僅作參考,別太信
更一般化的分析:
抽象工廠模式: 先看看下面的分析,我還沒搞明白反正,太亂了,具體問題就在於這個模式怎麼擴展
先明白兩個概念:
在有多個業務品種,業務分類時,有下面這麼幾個概念
1、產品族,也叫產品線,不同的產品族的產品,應該可以組裝成一件高等級產品,
如螺絲是一個產品族,分不同型號的螺絲,鐵板是一個產品族,分不同型號的鐵板,
門把手是一個產品族,分不同型號的門把手
——螺絲,鐵板,門把手就可以組成一個車門
2、產品等級:不同型號的螺絲,不同型號的鐵板,這個不同型號就是不同產品等級
所以對於產品而言:有兩種選擇
1、當產品族需要可擴展時:
有個:IProduct接口
有N個:AbstractXXProduct, N就是產品族的數量,如Abstract_Luosi,Abstract_Tieban,
Abstract_MenBaShou
對於每個產品族,有M個子類:Luosi_10, Luosi_12, Luosi_20, …,M就是產品等級的數量
——一共有M*N子類, N個抽象類,1個接口
擴展產品族只需要增加一個AbstractXXX, 和M個產品等級的子類
2、當產品等級需要可擴展時:
基本上增加產品族,就相當於增加產品線,
這不容易,但是增加產品等級,不需要擴展產品線,只要在
原先產品線上增加個等級就行
對於工廠而言:
——有個最大接口:AbstractFactory
——生產一個產品族,需要一個車間,就是一個XXXFactory,所以:
螺絲_Factory{
create_10號螺絲();
create_12號螺絲();
create_20號螺絲();
}
鐵板_Factory{
create_10號鐵板();
create_12號鐵板();
create_20號鐵板();
}
門把手_Factory{
create_10號門把手();
create_12號門把手();
create_20號門把手();
}
增加一個零件,就是增加一個產品族:
需要多一個AbstractXX類 需要多M個產品等級類,都繼承AbstractXXX類 需要多一個XXFactory類,作為工廠,生產M個產品等級的產品 本質上就是多了一條產品線增加一個產品等級,如30號門把手
需要多一個產品等級類,繼承Abstract門把手類 門把手_Factory需要增加一個方法
//人類的統一接口
public interface IHuman {
void say();
void getColor();
}
//實現類:黑人
public class BlackHuman implements IHuman{
@Override
public void say() {
System.out.println("我是黑種人");
}
@Override
public void getColor() {
System.out.println("黑色皮膚");
}
}
//實現類:黃人
public class YellowHuman implements IHuman{
@Override
public void say() {
System.out.println("我是黃種人");
}
@Override
public void getColor() {
System.out.println("黃色皮膚");
}
}
//白人略過...
//此時女娲造人,需要依賴於具體實現類
public static void main(String[] args) {
//===造白人
IHuman wh = new WhiteHuman();
wh.getColor();
wh.say();
//===造黑人
IHuman bh = new BlackHuman();
bh.getColor();
bh.say();
}
//加上個簡單工廠:
public class HumanFactory{
public static T createHuman(Class clazz) {
IHuman human = null;
try{
human = clazz.newInstance();
}catch(Exception e){
e.printStackTrace();
System.out.println("生成錯誤");
}
return (T)human;
}
}
//現在女娲是這樣工作:
public static void main(String[] args) {
//===造白人
IHuman wh = HumanFactory.createHuman(WhiteHuman.class);
wh.getColor();
wh.say();
//===造黑人
IHuman bh = HumanFactory.createHuman(BlackHuman.class);
bh.getColor();
bh.say();
//===造黃人
IHuman yh = HumanFactory.createHuman(YellowHuman.class);
yh.getColor();
yh.say();
}
分析代碼還是類似簡單工廠,因為產品體系還是很簡單,就是給工廠多了個接口
public abstract class AbstractHumanFactory {
public abstract T createHuman(Class clazz);
}
public class HumanFactory extends AbstractHumanFactory{
@Override
public T createHuman(Class clazz) {
IHuman human = null;
try{
human = clazz.newInstance();
}catch(Exception e){
e.printStackTrace();
System.out.println("生成錯誤");
}
return (T)human;
}
}
女娲端的代碼如下:
public static void main(String[] args) {
AbstractHumanFactory factory = new HumanFactory();
//===造白人
IHuman wh = factory.createHuman(WhiteHuman.class);
wh.getColor();
wh.say();
//===造黑人
IHuman bh = factory.createHuman(BlackHuman.class);
bh.getColor();
bh.say();
//===造黃人
IHuman yh = factory.createHuman(YellowHuman.class);
yh.getColor();
yh.say();
}
///===============定義產品族:男女===================///
public class AbstractMan implements IHuman{
}
public class AbstractWomen implements IHuman{
}
///===============定義產品等級:以男人為例=============///
public YellowMan extends AbstractMan{
}
///===============定義抽象工廠,每個產品族對應一個工廠,所以男人一個,女人一個===///
public abstract class AbstractHumanFactory {
public abstract IHuman createYellow();
public abstract IHuman createBlack();
public abstract IHuman createWhite();
}
public ManFactory extends AbstractHumanFactory{
}
public WomanFactory extends AbstractHumanFactory{
}
微信可以說是我們當下非常常用的手機軟件,很多人都會選擇它來進行交流。有的時候,我們在使用微信的過程中也會發現很多問題,今天,小編就來講講微信發不出信息怎麼辦
高效計算——RenderScriptRenderScript是安卓平台上很受谷歌推薦的一個高效計算平台,它能夠自動把計算任務分配到各個可用的計算核
從前面Android編譯系統環境初始化過程分析這篇文章可以知道,lunch命令其實是定義在build/envsetup.sh文件中的函數lunch提供的。與
在Android中,除了我們之前說過的sharedpreference可以用來保存數據之外,SQLiteDatabase應該是使用得最廣泛的一種數據保存方式。 SQLit