Fighting!

潜行者的沉默

Widget

什么是widget

一切皆是widget,是flutter应用用户界面的基本构建单元,每个widget都与最终的用户界面有密切相关

  • 抽象类继承了可诊断树(DiagnosticableTree)
  • 一个常量构造函数,可选参数key
  • 抽象方法createElement
  • 静态方法canUpdate,通过runtimeType和key判断

一个widget的定义如下

  • 一个结构元素(按钮,菜单)
  • 一个风格元素(字体,配色方案等)
  • 布局(padding)
  • 等等

widget的分类

主要需要了解的是StatelessWidget和StatefullWidget

  • StatelessWidget:无状态的,AssetImage,Text…
  • StatefulWidget:有状态的,Scrollable,Animatable..
  • Widget的介绍
    • 用于描述Element的配置
    • Widge他作为用户界面的一部分是不会改变的,被加载进Element(控制底层的渲染树)
    • Widget本身不包含状态或者可变数据,通过StatefulWidget.createState可以关联一个State
    • 一个Widget可以被多次插入视图树中,并被加载进Element中
    • 变量key和runtimeType用来判断Widget是否改变,是则重新加载
  • 构建 widget 的过程并不耗费资源,因为 Wiget 只是用来保存属性的容器。
  • 无法获取Widget在屏幕上的位置和大小,因为Widget就是一张蓝图,他只是描述了底层渲染对象应该具有的属性

StatelessWidget

  • 继承自Widget的抽象类
  • 重写了createElement方法名创建了StatelessElement对象
  • 一个build方法,创建一个Widget
  • 内部没有保存状态,UI界面创建后不会发生改变

StatefulWidget

  • 继承自Widget的抽象类
  • 重写了createElement方法名创建了StatefulElement对象
  • 一个createState方法,创建一个State
  • 内部保存状态,调用setState方法,变更UI

State

  • 泛型抽象类 T extend StatefulWidget
  • State的流程
    • launch->initState->didChangeDependencies->build->deactive->dispose->destroy
    • didUpdateWidget->build
    • initState:被插入到Widget树中被调用一次
    • didChangeDependencies:当state的依赖对象发生变化时调用
    • build:构建Widget时调用
    • didUpdateWidget:Widget重新构建时调用
    • deactive:当state对象被从树中移除调用
    • dispose:当state对象从树中被永久移除时调用,一般在此回调时释放资源

Element

  • Element是控件树上的实例
  • Element 通过 mount 方法插入到 Element Tree 中,创建了RenderObject对象

树 Widget Tree, Element Tree ,RenderObject Tree

  • Widget Tree -(createElement)> Element Tree -(createRenderObject)> RenderObject Tree
  • Widget是为了描述Element需要的配置,负责创建Element,决定Element是否需要被更新
  • Element表示Widget配置树的特定位置的一个实例,同时持有Widget和RenderObject,负责管理Widget的配置和RenderObject的渲染。Widget发生改变,didUpdateWidget->build不会重建E,Element,只会更新
  • RenderObject表示渲染树的一个对象,负责真正的渲染工作,比如测量大小,位置绘制等都是由RendeObject完成

key

  • 使用Key可以控制框架在Widget重建时与哪些其他Widget进行匹配
  • 包含有LocalKey和globalKey
    • LocalKey:ObjectKey,UniqueKey,ValueKey(PageStrageKey)
    • GlobalKey:LabeledGlobalKey,GlobalObjectKey

MaterialApp

Material应用是以MaterialApp Widget开始,主要封装了应用程序实现Material Design所需要的配置

  • 构造函数
    • 路由
    • 主题
    • 本地化
    • 性能监控,调试

Scaffold(脚手架)

在构造函数中,可以看出有App头布局,body内容,抽屉栏等元素控件,与原生Android有相似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const Scaffold({
Key key,
this.appBar,
this.body,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.floatingActionButtonAnimator,
this.persistentFooterButtons,
this.drawer,
this.endDrawer,
this.bottomNavigationBar,
this.bottomSheet,
this.backgroundColor,
this.resizeToAvoidBottomPadding,
this.resizeToAvoidBottomInset,
this.primary = true,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.extendBody = false,
this.extendBodyBehindAppBar = false,
this.drawerScrimColor,
this.drawerEdgeDragWidth,
})

Text

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Text(
this.data, { // 必要参数
Key key,
this.style, // 文字样式
this.strutStyle,
this.textAlign, // 文字居中
this.textDirection,
this.locale,
this.softWrap,
this.overflow,
this.textScaleFactor,
this.maxLines, // 最初
this.semanticsLabel,
this.textWidthBasis,
})

TextField

表单操作,输入用户名密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const TextField({
Key key,
this.controller,
this.focusNode, // 焦点
this.decoration = const InputDecoration(), // 设置输入样式
TextInputType keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
this.strutStyle,
this.textAlign = TextAlign.start,
this.textAlignVertical,
this.textDirection,
this.readOnly = false,
ToolbarOptions toolbarOptions,
this.showCursor,
this.autofocus = false,
this.obscureText = false, // 密码输入
this.autocorrect = true,
this.enableSuggestions = true,
this.maxLines = 1,
this.minLines,
this.expands = false,
this.maxLength,
this.maxLengthEnforced = true,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters, // 输入限制,手机号,数字 11位等
this.enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection = true,
this.onTap,
this.buildCounter,
this.scrollController,
this.scrollPhysics,
})

Image

  • AssetsImage:需要配置pubspec.yaml

BoxFit

图片的拉伸,填充控制

Icon

1
2
3
4
5
6
7
8
const Icon(
this.icon, { // 设置Icons.add 系统提供
Key key,
this.size,
this.color,
this.semanticLabel,
this.textDirection,
})

Dart的开发环境安装

概述

  1. Dart可以用来开发移动应用,web应用,开发命令行应用和服务端应用,主要有以下IDE可供选择
  2. VS Code:在其中安装Dart插件进行开发
  3. Android Studio:主要用于移动开发
  4. Web Storm,IntelliJ, DartPad在线运行

Dart SDK概要

  1. Dart SDK包含开发web,命令行和服务端应用所需要的库和命令行工具。如果是需要开发移动应用,只需要安装flutter即可

Dart SDK安装(homebrew)

  1. install
    1
    2
    brew tap dart-lang/dart
    brew install dart

Dart SDK升级

  1. update
    1
    brew upgrade dart
  2. 检查是否安装成功
    1
    dart --version

设置环境变量

1
2
3
4
vi .bash_profile

// click e 进入编辑模式
export Path=${PATH}:dart的安装目录

VS Code的开发环境

  1. VS Code的下载进行安装
  2. Dart的环境配置,在VS extesion中搜索并下载dart插件

DartPad 在线运行

  1. 打开dartpad.cn可以直接运行代码,但是如果有外部包导入,则需要VS Code

Dart基本概念

样例程序

1
2
3
4
5
6
7
8
9
10
// 定义一个函数
printInteger(int aNumber){
print('The number is $aNumber');
}

// Dart 程序从 main()函数开始执行
void main(){
var number = 42; // 声明并初始化一个变量
printInteger(number); // 调用一个函数
}
  1. // 表示注释
  2. int 表示数据类型
  3. main 顶级函数,应用程序的入口
  4. var 用于定义变量,可以不指定变量类型

重要概念

  1. 一切皆对象:所有变量引用的都是对象,数字,函数,null都是对象,都继承字Object类
  2. Dart声明变量类型可选:Dart可以进行类型推断,dynamic可以声明一个不确定的类型
  3. Dart支持泛型:List或者List(由任何类型对象组成的列表)
  4. Dart支持顶级函数,支持属于类或者对象的函数,支持嵌套函数:main
  5. Dart支持顶级变量,支持属于类或者对象的变量
  6. 标识符下划线开头表示库内私有:_number,_name()
  7. 标识符字母,数字,下划线,由字母或者下划线开头
  8. Dart表达式有值,语句没有值
  9. Dart工具可以显示警告和错误两种类型

关键字

分为1,2,3

  • 1表示上下文关键字,在特定的场合才有用
  • 2表示内置关键符
  • 3是1.0之后支持异步的关键字

变量

  1. 变量仅存储对象的引用
  2. 变量声明的时候可以不指定类型
  3. 未初始化的变量内容都为null
  4. 可以使用关键字final或者const修饰变量 final只能赋值一次,const为编译时常量,顶层的final变量或者类的final变量在其第一次使用的时候初始化

Dart内置类型

int

  • 长度不超过64位,具体取值范围依赖于不同的平台。在DartVM上其取值位于-2^63至2^63-1.编译吃JavaScript的Dart使用JavaScript数字,范围是-2^53~2^53-1之间

double

String

  • Dart字符串是UTF-16编码的字符序列。可以使用单引号或者双引号创建字符串
  • 可以使用+运算拼接字符串
  • 使用三个单引号或者三个双引号穿件多行字符串
  • 字符串前加上r作为前缀创建“raw”字符串(不会被做任何处理)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    var s1 = "dsadsa";
    var s2 = 'dadasd';

    var s3 = 'dasda\'';

    var s4 = "ab" + "cd";

    var s5 = "dsad""dasda";

    var s6 ='''
    dasfsa
    dsadas
    ''';

    var s8 = "dasdas is $a";

    const s10 = "a const";

Booleans

  • bool关键字表示布尔类型,布尔类型只有true和false,是编译时常量
  • Dart的类型安全不允许使用1,0做代码判断

Lists

  • Dart中数组由List对象表示的
  • 下标从0开始
  • List list = List();//固定长度为数组,无参表示可变长度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var list = [1,2,3];
    List list1 = new List();
    List list2 = List();
    list2.addAll(list);

    var temp = list2[0];

    var list3 = [0, ...list2];

    var list4 = [0, ...?list3];

    const list5 = [0,1,2];

    // list5[1] = 1; // 不能修改

Sets

  • Dart中使用sets表示元素无序,唯一的值
  • 支持Set字面量以及Set类型两种形式的set
  • Set字面量是在Dart2.2中加入的
    1
    2
    3
    4
    5
    var set1 = {'1'};
    var set2 = <int>{}; // 空的set, 不指定类型可用<dynamic>{}
    Set<int> set3 = Set();

    const set4 = {'a'};a

Maps

  • Dart中的Map通过map字面量和map类型来实现
  • 每个键只能出现一次,但是值可能出现重复
    1
    2
    3
    4
    5
    6
    7
    8
    var map = {1:"a", 2:"b"};
    Map map1 = Map();

    Map<int, String> map2 = Map();

    map2[0]; //0 是可以不是下标

    final map3 = const {1:"a", 2:"b"};

Runes

  • dart使用Runes来标识UTF-32编码的字符串
  • String类中的codeUniteAt和codeUnite属性返回16位代码单元。Runes属性可以获取字符串的Runes

Symbols

  • Symbols表示Dart中声明的操作符或者标识符,该类型的对象几乎不会被使用到
  • 可以使用在标识符前面加#来获取Symbols
  • Symbols字面量是编译时的常量

Dart方法

Dart是一种真正的面向对象的语言,所以函数也是对象并且类型为Function,这意味着函数可以被赋值给变量或者作为其他函数的参数。可以像调用函数一样调用Dart类的实例

参数

  • 函数可以有两张形式的参数;必要参数和可选参数
  • 必要参数定义在参数列表的前面
  • 可选参数定义在必要参数的后面
  • 可选参数
    • 可选参数分为命名参数和位置参数
    • 可选参数列表中任选其一使用,不能混用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int a(int a, int b,{int c, int d = 0, int f}){
return a+b;
}

void main(){
int c = a(2,3, c:4, d: 6);
}
// 使用参数名:参数值,的形式来指定命名参数
// 使用大括号的来指定命名参数
// 可以提供默认值
// @required注解来标识一个命名参数是必须的


int a(int a, int b,[int c, int d = 0, int f]){
return a+b;
}
// 使用中括号将一系列参数包裹起来作为位置参数
// 可以使用=为函数的位置参数设置默认值,默认值必须是常量默认是null

main()函数

  • 每个Dart程序都必须有一个main()顶级函数作为程序入口

函数作为一级对象

  • 可以将函数作为参数传递给另一个函数
  • 可以将函数赋值给另一个变量
1
2
3
4
5
6
7
var f=  printE;
var a = (e) => "dsada "; // 胖箭头语法

var b = (e){
return "xxx";
};

匿名函数

  • 没有名字的函数
    1
    2
    3
    ([[类型] 参数[,..]]){
    函数体;
    }

词法作用域

  • 变量的作用于在写代码的时候就确定了
  • 大括号内定义的变量只能在大括号内使用

词法闭包

  • 闭包即一个函数对象,即使函数对象的调用在它原始作用于范围之外,依然可以访问在它词法作用域内的变量

返回值

  • 所有函数都有返回值
  • 没哟显示返回语句的函数,默认返回 return null

运算符

流程控制语句

if else

  • if else
  • 三目运算 a == null? “guest”: a;
  • a ?? “guest”

for 循环语句

1
2
3
4
5
6
7
8
9
10
11
12
13
var listaa =['a', 'q', 'f'];

for (var item in listaa) {

}

for (var i = 0; i < listaa.length; i++) {

}

listaa.forEach((f){

});

while /do while

switch

break continue

异常

  • Dart能够Throw和catch异常,
  • Dart中的所有异常为非检查异常,方法不一定声明他们所抛出的异常,并且你也不需要捕获异常
  • Dart提供了Exception和Error类型,以及一些子类,也可以实现自己的异常类型

抛出异常

1
2
3
4
throw FormatException("Excepted at least 1 selection");

// 任意类型的异常对象
throw "out of IIams";

捕获异常

1
2
3
4
5
6
7
8
9
10
11
try {

} on XXXException {

} on Exception catch(e) {

} catch(e, s) {

} finally {

}

Dart是一个面向对象的编程语言,同时支持基于mixin的继承机制。每个对象都是一个类的实例,所有的累都继承Object。基于Mixin的继承意味着每个类都只有一个超类,一个类的代码可以在其他多个类继承
中重复使用

使用类的成员

  • 对象的成员由函数和数据(即方法和实例变量)组成,使用(.)来访问对象的实例变量或者方法

使用构造函数

  • 可以使用构造函数来创建一个对象。构造函数的命名方式可以为类名或者类名.标识符的形式
1
2
3
var p = Point();
var p2 = Point.fromJson({'x': 1, 'y': 2});
p.x = 3; // 使用x的setter方法

实例变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Point{
int x; //声明变量x并初始化为null
int y;
num z = 0; //声明变量z并初始化为0
}

void main(){
var p = Point();
// var p2 = Point.fromJson({'x': 1, 'y': 2});

p.x = 3; // 使用x的setter方法

assert(p.x == 3);// 使用x的getter方法
assert(p.y == null); //默认值为null
}

构造函数

  • 声明一个与类名一样的函数,即可声明一个构造函数
  • 对于大多数编程语言来说在构造函数中为变量赋值的的过程都类似,而Dart则提供了一种特殊的语法糖简化该步骤
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Point{
    int x; //声明变量x并初始化为null
    int y;
    num z = 0; //声明变量z并初始化为0

    // Point(int x, int y){
    // this.x = x;
    // this.y = y;
    // }

    // this.x,this.y, Dart特殊的语法糖构造函数赋值
    Point(this.x, this.y);
    }
  • 默认构造函数:如果没有声明构造函数,Dart会自动生成一个无参的构造函数,并且该构造函数会自动调用其父类的无参构造函数
  • 构造函数不会被继承:子类不会继承父类的构造函数
  • 命名式构造函数:可以为一个类声明多个命名式的构造函数来表达更明确的意图
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Point{
    int x; //声明变量x并初始化为null
    int y;
    num z = 0; //声明变量z并初始化为0

    // 命名式构造函数
    Point.origin(){
    this.x = 0;
    this.y = 0;
    }
    }
  • 重定向构造函数:有时候类中的构造函数会调用类中其他的构造函数,该重定向构造函数没有函数体,只需要在函数签名后面使用(:)指定需要重定向到的其他构造函数既可以
    1
    2
    // 委托实现给主构造函数
    Point.alongXAxis(int x):this(x, 0);
  • 常量构造函数:如果类生成的对象都是不变的,那么可以在生成这些对象时就将其变为编译时常量,你可以在类的构造函数前加上 const 关键字并确保所有实例均为final来实现该功能
    1
    2
    3
    4
    5
    class ImmutablePoint{
    static final ImmutablePoint point = const ImmutablePoint(0, 0);
    final int x, y;
    const ImmutablePoint(this.x, this.y);
    }
  • 工厂构造函数: 使用factory关键字表示类的构造函数将会令该构造函数变为工厂构造函数,这将意味着使用该构造函数构造类的实例时并非总是先返回新的实例对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Logger {
    final String name;

    static final Map<String, Logger> _cache = <String, Logger>{};
    factory Logger(String name){
    return _cache.putIfAbsent(name, () => Logger._internal(name));
    }

    static Logger _internal(String name){
    return Logger(name);
    }
    }

初始化列表

  • 在构造函数体执行之前初始化实例变量
    1
    2
    3
    4
    5
    Point.fromJson(Map<String, int> json){
    x = json['x'];
    y = json['y'];
    print("fromJson(): ($x, $y)" );
    }

调用父类构造函数

  • 构造函数调用顺序
    • 初始化列表
    • 父类的无参构造函数
    • 当前类的构造函数
  • 如果父类无无参构造函数,那么子类必须调用父类的其中一个构造函数,为子类的构造函数指定父类的构造函数只需要在构造函数体前使用(:)指定

方法

  • 实例方法:实例方法可以访问实例的变量和this
  • getter和setter的方法
  • 抽象方法:定义一个借口方法而不去做具体的实现让实现他的类去实现该方法,抽象方法只能存在与抽象类中

抽象类

  • 使用关键字abstract标识的类让类成为抽象类,抽象类将无法被实例化。抽象类常用于声明接口方法,有时候也会有具体的实现方法
  • 抽象类尝尝会包含抽象方法

扩展类

  • 继承 extend
  • 子类可以重写父类的实例方法,getter,setter方法

枚举类型

是一种特殊的类型,用于存储一些固定数量的常量

  • 使用关键字 enum
  • 每一个枚举值都有一个名为index成员变量的getter方法
  • 使用枚举类的values方法获取一个包含所有枚举值的列表
  • switch中使用枚举

使用mixin为类添加功能

mixin是一种在多继承中复用某各类中代码的方法模式

  • 定义一个类继承自Object并且不为该类定义构造函数,这个类就是Mixin类,通过关键字mixin替换class让其成为一个单纯的Mixin类
  • 使用with关键字并在其后面跟上Mixin类的名字来使用Mixin模式

静态变量和方法

static 关键字修饰

泛型

为什么使用功能泛型

  • 正确使用泛型可以生成更好的代码
  • 使用泛型减少重复代码
  • 构造方法时也可以使用泛型,在类名后用尖括号<..>将一个或多个类型包裹
    1
    2
    var nameSet = Set<String>.from(names);
    var views = Map<int, View>();
  • Dart的泛型类型是固化的,这意味着即便在运行时也会保持类的信息(java中的泛型是类型擦拭的)

限制参数化类型

  • 使用extends关键字限制

认识Java
  1. Java的起源是SUM公司开发的,后来被oracle收购
  2. Java的开发开发有三种
    • JAVA SE 桌面应用开发
    • JAVA ME 嵌入是开发
    • JAVA EE 企业平台开发,即互联网平台开发

Java语言特点

  1. Java是半开源的项目,可以接触底层代码
  2. Java是一种编程语言,面向对象的编程思想并且一直在拓展扩充
  3. 提供有方便的内存回收机制
  4. 避免了复杂的指针问题,使用更加简单的引用来代替指针
  5. Java是支持多线程开发的语言,使得在单位时间内的提升了处理能力
  6. Java提供了高效的网络处理能力,基于NIO实现了更加高效的网络传输能力
  7. Java具有良好的可移植性
  8. 足够简单

Java的可移植性

在于同一个程序可以在不同的操作系统中执行部署,减少开发难度。依赖于Java虚拟机JVM,不同操作系统拥有不同版本的JVM,实现了移植性。

Java程序运行机制
  • 编译型,解释型。Java是两种高级编程语言的结合,先编译成.class文件,再解释成计算机识别的机器指令
  • 编译命令:Javac.exe
  • 解释命令:Java.exe
  • Java程序的组成:Java源文件,字节码文件,机器码指令

JVM

  • 一台模拟的计算机,可以读取并处理经编译过的与平台无关的字节码class文件
  • java编译器针对JVM产生class文件,因此独立于平台
  • Java解释器负责将JVM的代码在特定的平台上运行

JDK的介绍

是Java的开发工具包,主要版本迭代,其中JRE是运行环境,只提供解释功能不提供程序的开发功能

  • 1995.05.23,JDK1.0发布, 1996年提供对外
  • 1998.12.04 JDK1.2,更名为Java2
  • 2005.05.23 十周年大会,JDK1.5 ,带来了新特性,决定了未来10的核心技术
  • 2014 JDK1.8,支持了Lambda,可以函数式编程
  • 2017 JDK1.9,提高了1.8稳定性
  • 2018 JDK1.10,属于1.9的稳定版

JDK的安装与配置

Java编程起步

创建HelloWorld.java文件,编写源文件,编写输出HelloWord的程序。Java程序是需要经过两次处理之后才能正常执行的

  • 对源代码进行编译:Javac xxx/HelloWord.java,会出现一个HelloWord.class的字节码文件,利用JVM进行编译,编译出一套与平台无关的字节码文件(*.class)
  • 在JVM上进行程序的解释执行Java xxx/HelloWord。解释的就是字节码文件,字节码文件的后缀是不需要编写的
  • 类的定义有两种形式,public class 类名, class 类名。第一种文件名必须与类名一致,第二种可以不一致,生成的*.class文件名与类名一致。一般情况是一个class并且以public修饰,类名是驼峰式
  • main方法,程序运行入口主方法

ClASSPATH环境属性

  • PATH: 是操作系统提供的路径配置,定义所有可执行程序的路径
  • CLASSPATH: 是JRE提供的,用于定义Java程序解释时类加载路径,默认是源文件的目录

注释

  • 单行注释 //
  • 多行注释 /* …. */
  • 文档注释 /** …. */

标识符和关键字

  • Java语言中有不同的结构:类,方法,变量结构等,对于结构的说明实际上就是标识符,是有命名规则的。
  • 关键字,是系统对于一些结构的的描述处理,有着特殊含义,public static final 等等

Java数据类型简介

  • 数据分类:基本数据类型(数字单元)分三大类,数值型,浮点型,字符型,引用数据类型(内存关系的使用)分数组,类,接口
    类型 包括 默认值
    基本数据类型
    整型 byte,short,int,long 0
    浮点型 float,double 0.0
    布尔型 boolea false
    字符型 char ‘\u0000’
    引用类型 数组,类,接口 null
  • 使用原则: 如果是描述数字首选int,double;如果要进行数据传输或者文字编码选择byte(二进制处理);处理中文char;描述内存或者文件大小,表的主键列long
  • 内存溢出:如果数值的操作超出了数值类型的范围就会陷入循环的现象,通过使用范围更大的数值类型解决
  • 浮点型数据,都是有小数点的。float 变量相乘会出现多出4位小数的历史bug
  • 整形数据进行相除,会得到整数部分,10/2 = 2, 除非进行转型
  • 字符类型char和整形int可以相互转换, 可以获取char字符在系统中的编码。大写字母 A(65)Z(90),小写字母a(97)z(112),大小写之间相差32位,数字范围‘0’(48)~’9’(57)
  • java可以保存中文是因为Java使用的是Unicode 16进制的编码
  • 布尔类型,只有true和false
  • 字符串。在Java中范围大的数据类型与范围小的数据类型操作,所有小的数据类型会自动转型为数据范围大的数据类型

运算符简介

  • 数学运算符: 加减乘除
  • 关系运算符:大小的比较,基本数据类型之间支持自动转型,字符类型可以转成int
  • 逻辑运算符:三目(赋值)运算
  • 位运算:二进制数的计算处理,(&与) (|或者) (^异或) (~反码)
    • & | 在进行逻辑运算的时候所有的条件都会执行
    • && || 若干个条件判断的时候,前面的返回来false 或者 true,后面的条件判断就不再执行

IF分支结构

针对关系表达式进行判断处理的的分支操作,关键字为if,else,,在多条件else if判断时需写上else

switch分支语句

是一个开关语句,它主要根据内容进行判断,支持String.注意添加break关键字,否则会继续执行。注意添加default关键字

while循环

for循环

for(定义循环的初始化数值;循环判断;修改循环数值){
循环执行;
}

  • 在明确循环次数的情况下优先选择for循环
  • 在不知道循环次数,但知道循坏条件下选择while

循坏控制

break:退出整个循坏的结构
continue: 在当前的语句之后中的代码不在执行,而直接执行后续的判断处理

方法的定义

  • 方法的命名规则
  • 是一段可以被重复调用的代码块

方法的重载

当方法名相同的时候,参数类型或者个数不同的时候就称为方法的重载。

  • 同一个方法名称,可以根据我们调用时传递的参数类型及个数实现不同方法体的调用
  • 方法的重载建议其返回值相同

方法的递归调用

  • 方法递归调用的结束条件
  • 每次调用的过程中一定要修改传递的参数条件
  • 递归操作虽然可以简化的调用,但是在实际开发中很少出现。容易栈溢出

面向对象的简介

  • 面向对象是以标准的模块化设计,并且可以重用特征,
  • 面向过程对于一个问题的解决方案不会考虑重用的设计
  • 面向对象设计的三大特征
    • 封装性:内部的操作对外部而言不可见,限制访问的安全
    • 继承性:在已有结构的的基础上进行功能的扩充
    • 多态性:在继承性的基础上扩充而来的概念,指的是类型的转换处理
  • 面向对象的开发步骤
    • OOA:面向对象分析
    • OOD: 面向对象的设计
    • OOP: 面向对象的编程

类与对象的简介

  • 类是对某一类事物的共性的抽象概念,而对象描述的是一个具体的产物
  • 类的组成
    • 成员属性:年龄,名字等
    • 操作方法:定义对象具有的处理行为

类与对象的定义

  • 类是一个独立的结构体,所以需要使用class来进行定义,主要由方法和属性所组成
  • 产生对象步骤
    • 声明对象
    • 实例化对象

对象内存分析

Person per = new Person();

  • 堆内存:保存的是对象实例的具体信息,在程序中堆内存的开辟是通过new完成的
  • 栈内存:保存的是一块堆内存的地址。通过地址找到堆内存,而后找到对象信息
  • 所有的对象在调用属性和方法之前必须进行实例化,否则无法使用报空指针NullPointException

对象引用分析

  • 类是引用数据类型
  • 存在引用传递,当两个引用变量指向同一个对象实例时,修改会对两个变量都生效

引用与垃圾产生分析

  • 垃圾的产生是没有任何栈内存所指向的堆内存空间
  • 一个栈内存只能保存一个堆内存的的地址数据,如果发生修改,则原保存的地址数据将彻底消失

成员属性的封装

对属性进行private的私有使用保护,不被外部程序随意修改数据

构造方法和匿名对象

  • 构造方法名称必须与类名称保持一致
  • 构造方法不允许设置任何返回值类型,无返回值
  • 构造方法在使用new关键字自动调用
  • 一个类至少存在有一个构造函数,永恒存在
  • 区分普通方法,两者对的调用时机不同
  • 匿名对象没有引用,调用结束就会进行回收

this关键字调用本类属性

  • 当前类中的属性:this.属性
  • 当前类的构造方法,普通方法
  • 描述当前对象

this调用方法

  • 构造方法在new实例化对象的时候调用
  • 普通方法在实例化对象后才可以调用
  • 评价一个代码的好坏
    • 代码结构可以重用,提供的是一个中间独立的支持
    • 我们的目标是没有重复
  • this()必须放在首行,必须保留程序出口避免死循环

声明static属性

  • 定义公共属性,通过类去修改属性值
  • static 属性值虽然定义在类中,但是其并不受类实例对象的控制
  • 在进行类设计首选非static属性(95%),而考虑到公共属性则考虑

声明static的方法

  • 通过类名调用
  • 不能加this
  • static 方法只允许调用static属性和方法
  • 非static方法允许调用static属性和方法
  • 所有的static属性和方法都可以在没有实例化对象的前提下使用,而非static则必须实例化后使用

普通代码块

  • 定义在方法中的代码块
  • 可以对方法进行一些结构的拆分,以防止相同变量名称所带来的的影响

构造块

构造块会有限于构造方法执行,并且每次实例化的时候都会调用构造块的代码

静态代码块

主要指通过static关键字定义的代码块

  • 静态代码块优先于构造代码块,并且不管有多少个实例对象,都只会执行一次。
  • 父类的代码块优先子类执行

数组的基本定义

  • 大量引用类型数据的创建
  • 数组的动态初始化,元素默认值为数据类型的默认值
  • 数组的静态初始化

阿里云Java学习路线

Java编程入门

主要讲解JavaSE的发展历史,JDK开发环境的搭建,CLASSPATH属性作用,Java程序基本结构、基本数据类型的划分及使用、程序结构、方法的定义与使用。

Java面向对象编程

面向对象是Java语言之中最为重要的特征,也是进一步学习Java的重要知识体系。在本课程之中将为读者详细的讲解面向对象的定义、类与对象的组成、内存分析、封装性、继承性、多态性等概念的全面分析

学习目标

  1. 什么是AOP(WHAT)
  2. AOP的使用 (HOW)
  3. 比较主流AOP方案的优缺点 (WHY)
  4. 基于AOP实现的业务开源库 (WHERE)

AOP的概念

什么是AOP

  • AOP与OOP一样,是一种程序设计的思想:面向切面编程(Aspect Oritented Programming),而非技术手段。思想的实现方式是一种技术,即通过预编译方式和运行期动态代理的方式实现程序功能的统一维护
  • AOP是OOP的延续,是软件开发中的热点。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,提高开发效率。

什么是OOP

  • OOP机面向对象编程(Object Oriented Programming),被理解为是一种将程序分解为封装数据及相关操作的对象的编程思想。它有三大特性:多态,继承,封装。其中封装指:隐藏对象的属性和实现细节,仅对外公开访问方法,控制在程序中属性的读和写的级别,以获得更加清晰高效的逻辑单元划分。这个程序的六大设计原则中的单一职责原则一致:一个类只负责一件事。
  • 因此针对上面的封装特性,他存在一个问题:当存在关注点聚焦的场景时,他无法很好的解决,因为一个关注点是面向所有而不是一个单一的类,不受类的边界的约束,因此它只能分散到各个类,方法中去。这样的好处是降低了类的复杂性,提高了程序的可维护性,但同时他也使代码变得啰嗦了,例如添加方法的调用日志,那就必须为所有的需要日志的方法添加调用日志的方法。

AOP和OOP的关系

  • 面对上述聚焦某个点的问题,AOP可以理解为是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或者阶段,以获得逻辑过程中各个部分之间低耦合性隔离效果。这两种思想在目标上有本质上的差异,但两者不是对立的,AOP是为了弥补OOP的不足。
  • OOP解决了竖向的问题,AOP则解决了横向的问题,有了AOP对程序的监控将更加简单清晰

使用的业务场景

日志记录,性能统计,安全控制,事务处理,异常处理等等

对比

阅读全文 »

数据库设计的三大范式

  1. 第一:原子性, 即不可拆分
  2. 第二:唯一性, id
  3. 第三:避免冗余性

学习大纲

  1. OSI七层模型介绍,TCP/IP模型介绍,Http协议的格式介绍
  2. OkHttp主线流程的源码阅读
  3. OkHttp源码阅读之线程池详解
  4. OkHttp责任链模式/建造者模式
  5. OkHttp整体框架
  6. OkHttp之Socket的请求与实现

1. 网路模型

  1. OSI七层模型,数据封装,解封装的过程
  2. TCP/IP模型, 应用层,传输层,网络层, 主机到网络层
  3. Http1.0, 请求响应后会马上断开;Http1.1,添加了keepAlive的长连接保持
  4. get请求,请求行,请求属性集;post请求,请求行,请求属性集,请求体长度,请求体类型

2. OkHttp主流程源码阅读

使用

1. 创建OkHttpClient的实例对象client
2. 创建请求对象Request的实例对象request
3. 通过client.newCall(request)获取到请求对象call
4. 通过请求对象call进行同步call.execute()请求或者call.enqueue(new CallBack())的异步请求

主流程

1. 通过构建者设计模式,创建出OkHttpClient的实例
2. 同样通过构建者设计模式,创建出Request的实例
3. client.newCall(request)内部通过Call的实现类RealCall,返回call的对象
4. 进行异步请求call.enqueue(new CallBack())不能重复请求,会调用分发器dispatcher.enqueue(new AsyncCall(responseCallback))
5. 在dispatcher中定义了双端的runningAsyncCalls和readyAsyncCalls及限制了同时访问同一个服务器为最大5个
6. 通过线程池调用executor.execute(asyncCall), asyncCall实现了Runnable
7. AsyncCall内部执行耗时execute方法,会调用责任链获得响应response
8. 成功与失败的回调,并且进行错误责任的划分

3. OkHttp源码阅读之线程池详解

1
2
3
4
5
6
7
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
  1. OkHttp中使用的线程池,采用了缓存方案。线程任务60s内执行完毕,则会复用线程。自定义线程工厂
  2. 守护线程的设置

4. OkHttp责任链模式/建造者模式

责任链模式关键是,拦截器集合,拦截器的一个管理类,index+1
建造者模式关键是构建对象

OkHttp整体框架

  1. http的默认端口是80, https是443
  2. callServerIntercept 建立连接,会做连接池的复用
  3. 网络层是在路由器之间的传输ip数据包,数据链路层是交换机间的传输是帧,最后是物理机的比特流的传输
  4. OkHttp封装了Socket,对socket进行了复用,缓存机制
  5. 连接池的设计,定义了一个线程池和一个清理连接对象的线程,通过连接对象的空闲时间和允许的最大空闲时间来回收连接池
0%