首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

Unity C#基础之 反射反射,程序员的快乐

反射反射,程序员的快乐 这句话想必大家都经常听过,基本上在绝大多数的框架和一些设计模式中都能看到反射的身影(MVC、IOC、AOP、O/RM), 反射:是.Net Framework提供的一个帮助类库,可以访问dll的metadata,并且使用它。 反射给我们带来的优缺点如下: 极大的解耦 动态创建 代码多编写量大 避开编译器的检查 性能问题 反射性能要差普通的400+倍 但是绝对值小,几乎不影响项目性能 而且还可以优化,空间换时间(非常适合泛型缓存) 下面一些示例介绍一些反射比较实用的基本用法 (Unity版本:2017.3.0 P4 .NET 4.6) 示例工程下载 using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEngine; public class InvokeReflection : MonoBehaviour { void Start() { Learn00(); } public void Learn00() { /* *System.Reflection.Assembly类有两个静态方法:Assembly.Load(string assemblyname)和Assembly.LoadFrom(string filename) 。 * 通常用这两个方法把程序集加载到应用程序域中。 如果你希望加载的程序集超出了CLR的预定探查范围,你可以用 Assembly.LoadFrom直接从一个文件位置加载程序集。 * Assembly.LoadFrom()和Assembly.LoadFile(),两者的主要区别有两点: * 一:Assembly.LoadFile()只载入指定的dll文件,而不会自动加载相关的dll文件。如果下文例子使用Assembly.LoadFile()加载SayHello.dll,那么程序就只会加载 * SayHello.dll而不会去加载SayHello.dll引用的BaseClass.dll文件。 *二:用Assembly.LoadFrom()载入一个Assembly时,会先检查前面是否已经载入过相同名字的Assembly; * 而Assembly.LoadFile()则不会做类似的检查。 */ //C:\Users\Administrator\Desktop\New Unity Project\Assets\DLL Assembly assemly2 = Assembly.LoadFrom(@"C:\Users\Administrator\Desktop\New Unity Project\Assets\Scripts\TestReflection.dll"); Assembly assemly1 = Assembly.LoadFile(@"C:\Users\Administrator\Desktop\New Unity Project\Assets\Scripts\TestReflection.dll"); Assembly assemly = Assembly.Load("TestReflection");//1填加DLL Type testType = assemly.GetType("HaiLan.TestReflection.TestReflectionDLL");//2获取对应的类信息,需要填加对应的命名空间 object oTestReflectionDLL = Activator.CreateInstance(testType);//3 创建对象 IReflectionDLL iTestReflectionDLL = oTestReflectionDLL as IReflectionDLL;//4 类型转换 iTestReflectionDLL.TestShow1();//5 方法调用 foreach (var item in assemly.GetModules()) { Debug.Log(item.Name);//打印结果 TestReflection.dll } foreach (var type in assemly.GetTypes()) { Debug.Log(type.Name); foreach (var item in type.GetMethods()) { Debug.Log(item.Name); } } } } 运行结果如下: public void Learn01() { Console.WriteLine("************************Reflection*****************"); Assembly assemly = Assembly.Load("TestReflection"); Type testType = assemly.GetType("HaiLan.TestReflection.TestReflectionDLL"); object oTest1 = Activator.CreateInstance(testType); object oTest2 = Activator.CreateInstance(testType, new object[] { }); object oTest3 = Activator.CreateInstance(testType, new object[] { 9257 }); object oTest4 = Activator.CreateInstance(testType, new object[] { "海澜" }); Type genericType = assemly.GetType("HaiLan.TestReflection.GenericClass`3");//泛型类还有3个未指定的类型 Type genericNewType = genericType.MakeGenericType(typeof(int), typeof(string), typeof(InvokeReflection)); object oGeneric = Activator.CreateInstance(genericNewType); GenericClass<int,string, InvokeReflection> TempGenericClass = oGeneric as GenericClass<int, string, InvokeReflection>; TempGenericClass.Show(9257,"海澜", this); Type singletonType = assemly.GetType("HaiLan.TestReflection.Singleton"); object oSingleton1 = Activator.CreateInstance(singletonType, true);//单例模型依然可以创建新类 object oSingleton2 = Activator.CreateInstance(singletonType, true); object oSingleton3 = Activator.CreateInstance(singletonType, true); } 运行结果如下: public void Learn02() { Assembly assemly = Assembly.Load("TestReflection"); Type testType = assemly.GetType("HaiLan.TestReflection.ReflectionTest"); object oTest = Activator.CreateInstance(testType); { MethodInfo method = testType.GetMethod("Show1");//以前写的具体方法,换成字符串 method.Invoke(oTest, null); } { MethodInfo method = testType.GetMethod("Show2");//带参数 method.Invoke(oTest, new object[] { 9257 }); } { MethodInfo method = testType.GetMethod("Show5");//静态 method.Invoke(oTest, new object[] { "海澜" }); method.Invoke(null, new object[] { "海澜" }); } { MethodInfo method = testType.GetMethod("Show3", new Type[] { });//重载方法 method.Invoke(oTest, new object[] { }); } { MethodInfo method = testType.GetMethod("Show3", new Type[] { typeof(int) });//重载方法 method.Invoke(oTest, new object[] { 9257 }); } { MethodInfo method = testType.GetMethod("Show3", new Type[] { typeof(string) });//重载方法 method.Invoke(oTest, new object[] { "海澜" }); } { MethodInfo method = testType.GetMethod("Show3", new Type[] { typeof(int), typeof(string) });//重载方法 method.Invoke(oTest, new object[] { 9257, "海澜" }); } { MethodInfo method = testType.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });//重载方法 method.Invoke(oTest, new object[] { "海澜", 9257 }); } { MethodInfo method = testType.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic);//私有方法 method.Invoke(oTest, new object[] { "海澜" }); } { Type genericType = assemly.GetType("HaiLan.TestReflection.GenericMethod"); object oGeneric = Activator.CreateInstance(genericType); MethodInfo method = genericType.GetMethod("Show"); //MethodInfo method = genericType.GetMethod("Show`3");//错误写法,应为在编译期间就是无法通过的 MethodInfo methodNew = method.MakeGenericMethod(typeof(int), typeof(string), typeof(int)); methodNew.Invoke(oGeneric, new object[] { 9257, "海澜", 92570 }); } } 运行结果如下: public void Learn03() { { People people = new People(); people.Id = 9257; people.Name = "海澜"; people.Description = "菜鸟海澜"; Debug.Log($"people.Id={people.Id}"); Debug.Log($"people.Name={people.Name}"); Debug.Log($"people.Description={people.Description}"); } { Type type = typeof(People); object oPeople = Activator.CreateInstance(type); foreach (var item in type.GetProperties())//反射可以给对象的属性 动态 赋值/获取值, { Debug.Log(item.Name); Debug.Log(item.GetValue(oPeople)); if (item.Name.Equals("Id")) { item.SetValue(oPeople, 1235); } else if (item.Name.Equals("Name")) { item.SetValue(oPeople, "菜鸟海澜"); } Debug.Log(item.GetValue(oPeople)); } foreach (var item in type.GetFields())//反射可以给对象的字段 动态 赋值/获取值, { Debug.Log(item.Name); Debug.Log(item.GetValue(oPeople)); if (item.Name.Equals("Description")) item.SetValue(oPeople, "菜鸟海澜,ID:9257"); Debug.Log(item.GetValue(oPeople)); } } } 运行结果如下: 反射介绍如下: 反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。 反射的用途: 使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。 使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。 使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。 使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。 使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。 反射用到的命名空间: System.Reflection System.Type System.Reflection.Assembly 反射用到的主要类: System.Type 类--通过这个类可以访问任何给定数据类型的信息。 System.Reflection.Assembly类--它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。 System.Type类: System.Type 类对于反射起着核心的作用。但它是一个抽象的基类,Type有与每种数据类型对应的派生 类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息。 获取给定类型的Type引用有3种常用方式: ● 使用 C# typeof 运算符。 Type t = typeof(string); ● 使用对象GetType()方法。 string s = "grayworm"; Type t = s.GetType(); ● 还可以调用Type类的静态方法GetType()。 Type t = Type.GetType("System.String"); 上面这三类代码都是获取string类型的Type,在取出string类型的Type引用t后,我们就可以通过t来探测string类型的结构了。 string n = "grayworm"; Type t = n.GetType(); foreach (MemberInfo mi in t.GetMembers()) { Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name); } Type类的属性: Name 数据类型名 FullName 数据类型的完全限定名(包括命名空间名) Namespace 定义数据类型的命名空间名 IsAbstract 指示该类型是否是抽象类型 IsArray 指示该类型是否是数组 IsClass 指示该类型是否是类 IsEnum 指示该类型是否是枚举 IsInterface 指示该类型是否是接口 IsPublic 指示该类型是否是公有的 IsSealed 指示该类型是否是密封类 IsValueType 指示该类型是否是值类型 Type类的方法: GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息 GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息 GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息 GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息 GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息 GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息 GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息 可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。 //查看类中的构造方法: NewClassw nc = new NewClassw(); Type t = nc.GetType(); ConstructorInfo[] ci = t.GetConstructors(); //获取类的所有构造函数 foreach (ConstructorInfo c in ci) //遍历每一个构造函数 { ParameterInfo[] ps = c.GetParameters(); //取出每个构造函数的所有参数 foreach (ParameterInfo pi in ps) //遍历并打印所该构造函数的所有参数 { Console.Write(pi.ParameterType.ToString()+" "+pi.Name+","); } Console.WriteLine(); } 用构造函数动态生成对象: Type t = typeof(NewClassw); Type[] pt = new Type[2]; pt[0] = typeof(string); pt[1] = typeof(string); //根据参数类型获取构造函数 ConstructorInfo ci = t.GetConstructor(pt); //构造Object数组,作为构造函数的输入参数 object[] obj = new object[2]{"grayworm","hi.baidu.com/grayworm"}; //调用构造函数生成对象 object o = ci.Invoke(obj); //调用生成的对象的方法测试是否对象生成成功 //((NewClassw)o).show(); 用Activator生成对象: Type t = typeof(NewClassw); //构造函数的参数 object[] obj = new object[2] { "grayworm", "hi.baidu.com/grayworm" }; //用Activator的CreateInstance静态方法,生成新对象 object o = Activator.CreateInstance(t,"grayworm","hi.baidu.com/grayworm"); //((NewClassw)o).show(); //查看类中的属性: NewClassw nc = new NewClassw(); Type t = nc.GetType(); PropertyInfo[] pis = t.GetProperties(); foreach(PropertyInfo pi in pis) { Console.WriteLine(pi.Name); } //查看类中的public方法: NewClassw nc = new NewClassw(); Type t = nc.GetType(); MethodInfo[] mis = t.GetMethods(); foreach (MethodInfo mi in mis) { Console.WriteLine(mi.ReturnType+" "+mi.Name); } //查看类中的public字段 NewClassw nc = new NewClassw(); Type t = nc.GetType(); FieldInfo[] fis = t.GetFields(); foreach (FieldInfo fi in fis) { Console.WriteLine(fi.Name); } //用反射生成对象,并调用属性、方法和字段进行操作 NewClassw nc = new NewClassw(); Type t = nc.GetType(); object obj = Activator.CreateInstance(t); //取得ID字段 FieldInfo fi = t.GetField("ID"); //给ID字段赋值 fi.SetValue(obj, "k001"); //取得MyName属性 PropertyInfo pi1 = t.GetProperty("MyName"); //给MyName属性赋值 pi1.SetValue(obj, "grayworm", null); PropertyInfo pi2 = t.GetProperty("MyInfo"); pi2.SetValue(obj, "hi.baidu.com/grayworm", null); //取得show方法 MethodInfo mi = t.GetMethod("show"); //调用show方法 mi.Invoke(obj, null); System.Reflection.Assembly类 Assembly类可以获得程序集的信息,也可以动态的加载程序集,以及在程序集中查找类型信息,并创 建该类型的实例。 使用Assembly类可以降低程序集之间的耦合,有利于软件结构的合理化。 通过程序集名称返回Assembly对象 Assembly ass = Assembly.Load("ClassLibrary831"); 通过DLL文件名称返回Assembly对象 Assembly ass = Assembly.LoadFrom("ClassLibrary831.dll"); 通过Assembly获取程序集中类 Type t = ass.GetType("ClassLibrary831.NewClass"); //参数必须是类的全名 通过Assembly获取程序集中所有的类 Type[] t = ass.GetTypes(); //通过程序集的名称反射 Assembly ass = Assembly.Load("ClassLibrary831"); Type t = ass.GetType("ClassLibrary831.NewClass"); object o = Activator.CreateInstance(t, "grayworm", "http://hi.baidu.com/grayworm"); MethodInfo mi = t.GetMethod("show"); mi.Invoke(o, null); //通过DLL文件全名反射其中的所有类型 Assembly assembly = Assembly.LoadFrom("xxx.dll的路径"); Type[] aa = a.GetTypes(); foreach(Type t in aa) { if(t.FullName == "a.b.c") { object o = Activator.CreateInstance(t); } }

优秀的个人博客,低调大师

JavaScript进阶【一】JavaScript模块化开发的基础知识

版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79249047 //模块化的最初写法 //1.最初写法 //下面的m1和m2就组成了一个模块 //缺点:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。 function m1() { //--- } function m2() { //--- } //2.对象的写法 //可以把模块写成一个对象,所有的模块成员都放到这个对象里面。 var module = new Object({ _count: 0, m1 : function () { //--- alert("函数1!"); }, m2 : function () { //--- alert("函数2!"); } }); //对象方法模块的使用(开始调用模块里面的成员) //module.m1(); //module.m2(); //缺点:这样的写法会暴露所有模块成员,内部状态可以被外部改写 //module._count = 5; //alert(module._count); //3.立即执行函数的写法 var module1 = (function () { var _count1 = 0; var m1 = function () { //---- } var m2 = function () { //---- } return { m1 : m1, m2 : m2 } })(); //使用上面的写法,外部代码无法读取内部的_count变量。 //alert(module1._count1); //error //4.放大模式 //给模块module1来添加一个新的方法m3(),然后返回新的module1模块 var module1 = (function (mod) { mod.m3 = function () { //--- }; return mod; })(module1); //5.宽放大模式 //"宽放大模式"就是"立即执行函数"的参数可以是空对象。 var module1 = (function (mod) { //--- return mod; })(window.module1 || {}); //6.输入全局变量 //独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互 //为了在模块内部调用全局变量,必须显式地将其他变量输入模块。 /*var module1 = (function ($, YAHOO) { //--- })(JQuery, YAHOO); */ //7.模块的规范 //有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。 //目前,通行的Javascript模块规范共有两种:CommonJS和AMD。 //加载数学模块math.js //这里的require()用于加载模块 var math = require('math'); //调用模块提供的方法 var result = math.add(1, 2); alert(result); //浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。 //上面的调用模块方式只能在math模块加载完毕之后,才能执行模块中的add方法 //10.AMD("异步模块定义) //第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。 //require([module], callback); //math.add()与math模块加载不是同步的,浏览器不会发生假死。所以很显然,AMD比较适合浏览器环境。 //目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js。 require(['math', function (math) { math.add(1, 2); }]); //----------------require.js的使用方法-------------------------- //最初的导入.js文件的写法 /* * <script src="1.js"></script> <script src="2.js"></script> <script src="3.js"></script> <script src="4.js"></script> <script src="5.js"></script> <script src="6.js"></script> * * 【缺点】 * 1.加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长 * 2.由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。 * * 【require.js】解决的问题如下: * (1)实现js文件的异步加载,避免网页失去响应; (2)管理模块之间的依赖性,便于代码的编写和维护。 * */ /** * require.js的具体使用方法如下: */ //使用require.js来进行模块化开发 //alert("main.js 加载完成!"); /* * 真正常见的情况是,主模块依赖于其他模块,这时就要使用AMD规范定义的的require()函数。 * // main.js require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){ // some code here }); * * 第一个参数是一个数组,表示所依赖的模块,上例就是['moduleA', 'moduleB', 'moduleC'],即主模块依赖这三个模块; * 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。 * [注]加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块 * * * require()异步加载moduleA,moduleB和moduleC,浏览器不会失去响应; * 它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。 * 假定主模块依赖jquery、underscore和backbone这三个模块,main.js就可以这样写 * require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){ // some code here }); * require.js会先加载jQuery、underscore和backbone,然后再运行回调函数。主模块的代码就写在回调函数中。 * */ //使用AMD规范定义的require()函数 //,require.js假定这三个模块与main.js在同一个目录,文件名分别为jquery.js,underscore.js和backbone.js, require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){ // some code here }); //模块的加载 //使用require.config()方法,我们可以对模块的加载行为进行自定义 require.config({ //这里指定了三个模块的文件名字以及文件的路径 paths : { "jquery" : "lib/jquery.min", "underscore" : "lib/underscore.min", "backbone" : "lib/backbone.min" } }); //也可以改变基目录来实现 require.config({ //指定基目录 baseUrl : "js/lib", //这里指定了三个模块的文件名字以及文件的路径 paths : { "jquery" : "jquery.min", "underscore" : "underscore.min", "backbone" : "backbone.min" } }); //也可以使用目标服务器中的地址来加载js文件 //require.js要求, 每一个模块都是一个单独的js 文件 //当模块部署完毕以后,可以用这个require.js提供的工具将多个模块合并在一个文件中,减少HTTP请求数 require.config({ paths :{ "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min" } }); //加载我自己定义的math.js 下面的模块的方法如下 require(['math'], function (math) { alert(math.add(1, 2)); //经过测试,也完美运行了 }); //在这里去调用我的相减的模块 require(['plus'], function (plus) { //这里的意思是指去嗲用plus这个模块下面的result模块 alert(plus.result(10, 5)); //5 }); //加载非规范的模块 //underscore和backbone这两个库,都没有采用AMD规范编写。如果要加载它们的话,必须先定义它们的特征。 require.config({ //shim属性,专门用来配置不兼容的模块 shim : { 'underscore':{ exports:'_' }, //(1)exports值(输出的变量名),表明这个模块外部调用时的名称; //(2)deps数组,表明该模块的依赖性。 'backbone':{ deps:['underscore', 'jquery'], exports:'Backbone' } } }); //来配置一个JQuery插件 require.config({ shim : { 'jquery.scroll':{ //这个模块的依赖项为jquery.js deps:['jquery'], //这个模块外部调用的名称就使用query.fn.scroll exports:'Jquery.fn.scroll' } } }); //其他的require.js插件 //domready插件,可以让回调函数在页面DOM结构加载完成后再运行。 require(['domready!', function (doc) { //当Dom 元素节点加载完毕之后再运行 }]); //text和image插件,则是允许require.js加载文本和图片文件。 define([ 'text!review.txt', 'image!cat,jpg' ], function (review, cat) { console.log(review); //把图片文件加载进来 document.body.appendChild(cat); } ); //这里我定义了一个数学模块 //5.AMD模板的写法 //模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。 //实例:有一个main.js文件, 定义了一个math模块; math.js的写法如下 /*define(function () { var add = function (x, y) { return x + y; } return { add: add }; }); */ //如果这个模块还依赖其他模块的写法如下 //当require.js 在加载这个math.js模块的时候, 就会先加载plus.js 文件 define(['plus'], function (plus) { var add = function (x, y) { alert("plus.js这个依赖项加载完毕!") return x + y; } return { add: add }; }); //我这里又是一个模块 define(function () { alert("开始加载plus.js这个依赖项!"); var minus = function (x, y) { return x - y; }; return { result : minus } }); <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--async属性表示这个文件需要异步加载; 避免网页失去响应; IE不支持这个属性,只支持defer,所以把defer也写上--> <!--<script type="text/javascript" src="require2.3.5.js" defer async="true"></script>--> <!--<script type="text/javascript" src="main.js"></script>--> <!--加载require.js以后,下一步就要加载我们自己的代码;两个写在一块的写法如下 data-main属性的作用是,指定网页程序的主模块; 也就是main.js 文件, 这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js, 所以可以把main.js简写成main。 --> <script src="require2.3.5.js" defer async="true" data-main="main"></script> </head> <body> js 模块化开发测试 </body> </html>

优秀的个人博客,低调大师

先搞懂这八大基础概念,再谈机器学习入门!

准备好开始AI了吗?可能你已经开始了在机器学习领域的实践学习,但是依然想要扩展你的知识并进一步了解那些你听过却没有时间了解的话题。 这些机器学习的专业术语能够简要地介绍最重要的机器学习概念—包括商业界和科技界都感兴趣的话题。在你遇到一位AI指导者之前,这是一份不详尽,但清楚易懂又方便在工作、面试前快速浏览的内容。 概览: 自然语言处理 数据库 计算机视觉 监督学习 无监督学习 强化学习 神经网络 过拟合 1 自然语言处理 自然语言处理对于许多机器学习方法来说是一个常用的概念,它使得计算机理解并使用人所读或所写的语言来执行操作成为了可能。 自然语言处理最重要的最有用的实例: ① 文本分类和排序 这项任务的目标是对一个文本进行预测标签(类别)或对列表中相关联的文本进行排序。它能够用于过滤垃圾邮件(预测一封电子邮件是否是垃圾邮件),或进行文本内容分类(从网络上筛选出那些与你的竞争者相关的文章)。 ② 情感分析 句子分析是为了确定一个人对某个主题的看法或情感反应,如正面或负面情绪,生气,讽刺等。它广泛应用于用户满意度调查(如对产品的评论进行分析)。 ③ 文件摘要 文件摘要是用一些方法来得到长文本(如文档,研究论文)短且达意的描述。对自然语言处理方向感兴趣吗?请进一步阅读人工智能关于自然语言处理方向的文章:https://sigmoidal.io/boosting-your-solutions-with-nlp/ ④ 命名实体识别 命名实体识别算法是用于处理一系列杂乱的文本并识别目标(实体)预定义的类别,如人,公司名称,日期,价格,标题等等。它能够将杂乱的文本信息转换成规则的类表的格式,来实现文本的快速分析。 ⑤ 语音识别 语音识别技术是用于得到人所讲的一段语音信号的文本表达。你可能听说过Siri助手?这就是语音识别应用的一个最好的例子。 ⑥ 自然语言的理解和生成 自然语言的理解是通过计算机,将人类生成的文本转换成更正式的表达。反过来,自然语言生成技术是将一些正式又有逻辑性的表达转换成类人的生成文本。如今,自然语言理解和生成主要用于聊天机器人和报告的自动生成。 从概念上来说,它与实体命名识别任务是相反的。 ⑦ 机器翻译 机器翻译是将一段文本或语音自动从一种语言翻译成另一种语言的一项任务。请见:https://youtu.be/Io0VfObzntA 2 数据库 数据库是机器学习一个必要的组成部分。如果你想构建一个机器学习系统,你要么可以从公众资源中得到数据,要么需要自己收集数据。所有的用于构建和测试机器学习模型的数据集合成为数据库。基本上,数据科学家会将数据划分为三个部分: 训练数据:训练数据是用于训练模型。这意味着机器学习模型需要认识并通过学习得到数据的模式以及确定预测过程中最重要的数据特征。 验证数据:验证数据是用于微调模型参数和比较不同模型来确定最优的模型。验证数据应该不同于训练数据,且不能用于训练阶段。否则,模型将出现过拟合现象,且对新的数据泛化不佳。 测试数据:这看起来似乎有些单调,但这通常是第三个也是最后的测试集(经常也被称为对抗数据)。一旦最终的模型确定,它就用于测试模型在从未见过的数据集上的表现,如这些数据从未在构建模型或确定模型时使用过。 图像:混合使用t-SNE和Jonker-Volgenant算法得到的MNIST数据库的可视化结果。T-SNE是一种广泛使用的降维算法,通过压缩数据的表达来得到更好的可视化和进一步处理。 3 计算机视觉 计算机视觉是一个专注于分析并深层次理解图像和视频数据的人工智能领域。计算机视觉领域最常见的问题包括: ① 图像分类 图像分类是教模型去识别给定的图像的一种计算机视觉任务。例如,训练一个模型去识别公共场景下的多个物体(这可以应用于自动驾驶)。 ② 目标检测 目标检测是教模型从一系列预定义的类别中检测出某一类别的实例,并用矩形框框注出来的一种计算机视觉任务。例如,利用目标检测来构建人脸识别系统。模型可以在图片中检测出每张脸并画出对应的矩形框(顺便说下,图像分类系统只能识别出一张图片中是否有脸的存在,而不能检测出脸的位置,而目标检测系统就可以)。 ③ 图像分割 图像分割是训练模型去标注类的每一个像素值,并能大致确定给定像素所属的预定义类别的一种计算机视觉任务。 显著性检测 显著性检测是训练模型产生最显著区域的一种计算机视觉任务。这可以用于确定视频中广告牌的位置。需要详细了解计算机视觉?请阅读https://sigmoidal.io/dl-computer-vision-beyond-classification/ 4 监督学习 监督学习是用实例来教模型学习的一类机器学习模型集合。这意味着用于监督学习任务的数据需要被标注(指定正确的,真实类别)。例如,如果我们想要构建一个机器学习模型用于识别一个给定的文本是否被标记过的,我们需要给模型提供一个标记过的样本集 (文本+信息,是否该文本被标记过)。给定一个新的,未见过的例子,模型能够预测它的目标,例如,规定样本的标签,1表示标记过的而0表示未标记的。 5 无监督学习 相比于监督学习,无监督学习模型是通过观察来进行自我学习。算法所用的数据是未标记过的(即提供给算法的是没有真实标签值的数据)。无监督学习模型能够发现不同输入之间的相关关系。最重要的无监督学习技术是聚类方法。对于给定的数据,模型能够得到输入的不同聚类(对于相似的数据聚合在同一类中),并能将新的、未见过的输入归入到相似的聚类中。 6 强化学习 强化学习区别于先前我们提到的那些方法。强化学习算法一种“游戏”的过程,其目标是最大化 “游戏奖励”。该算法通过反复的实验来尝试确定不同的 “走法”,并查看哪种方式能够最大化 “游戏收益” 最广为人知的强化学习例子就是教计算机来解决魔方问题或下象棋,但是强化学习能解决的问题不仅只有游戏。最近,强化学习大量地应用于实时竞价,其模型负责为一个广告竞拍价格而它的报酬是用户的转换率。 想要学习人工智能在实时竞价和程序化广告中的应用吗?详见:https://sigmoidal.io/ai-for-advertising/ 7 神经网络 神经网络是一个非常广泛的机器学习模型集合。它的主要思想是模拟人类大脑的行为来处理数据。就像大脑中真实神经元之间相互连接形成的网络一样,人工神经网络由多层组成。每层都是一系列神经元的集合,这些神经元负责检测不同的食物。一个神经网络能够连续地处理数据,这意味着只有第一层才与输入直接相连,随着模型层数的增加,模型将学到越来越复杂的数据结构。当层数大量地增加,模型通常就是一个所谓的深度学习模型。很难给一个深度网络确定一个特定的网络层数,10年前通常3层神经网络就可谓深,而如今通常需要20层。 神经网络有许许多多不同的变体,最常用的是: 卷积神经网络—它给计算机视觉任务带来了巨大的突破(而如今,它同样对于解决自然语言处理问题有很大帮助)。 循环神经网络—被设计为处理具有序列特征的数据,如文本或股票票价。这是个相对古老的神经网络,但随着过去20年现代计算机计算能力的突飞猛进,使得它的训练变得容易并在很多时候得以应用。 全连接神经网络—这是处理静态/表格式数据最简单的模型。 8 过拟合 当模型从不充分的数据中学习会产生偏差,这对模型会有负面的影响。这是个很常见,也很重要的问题。 当你在不同的时间进入一个面包坊,而每一次所剩下的蛋糕都没有你喜欢的,那么你可能会对这个面包坊失望,即使有很多其他的顾客可能会对剩下的蛋糕满意。如果你是个机器学习模型,可以说你对这一小数量样本产生了过拟合现象—要构建一个具有偏置量的模型,其得到的表示才不会过度拟合真实数据。 当过拟合现象发生,它通常意味着模型将随机噪声当作数据,并作为一个重要的信号去拟合它,这就是为什么模型在新数据上的表现会出现退化(噪声也有差异)。这在一些非常复杂的模型如神经网络或加速梯度模型上是很常见的。 想象构建一个模型来检测文章中出现的有关奥运的特定体育项目。由于所用的训练集与文章是由偏差的,模型可能学习到诸如 “奥运”这样词的特征,而无法检测到那些未包含该词的文章。 原文链接:https://mp.weixin.qq.com/s?__biz=MzI0ODcxODk5OA==&mid=2247492171&idx=2&sn=f61d47045f6bf0ffd2c1e25b9a670bbd&chksm=e99ed1b2dee958a4b155cc526de04db4a85f458c5a14f597252b40ebc7ff77c7529f1757497a&scene=21#wechat_redirect

优秀的个人博客,低调大师

Android基础笔记(十四)- 内容提供者读取联系人

利用内容提供者读取联系人 利用内容提供者插入联系人 内容观察者的原理 利用内容观察者监听系统应用数据库或者自己应用数据库的变化 利用内容提供者读取联系人 读取联系人相对于读取短信来说就复杂非常多了,我们一步一步来吧。 先看看一下联系人的数据库,是位于什么地方! 既然非常复杂,我们就一步步分析吧,我们把contacts2.db导出到电脑中,并使用SQLite数据库软件打开。 你能够看到一大堆的表和视图,当然我们使用到的也仅仅有三张。各自是raw_contacts、data、mimetypes分别存储着联系人ID、联系人数据、联系人数据相应的MIMIE类型。 我们逐个看一下,首先是raw_contacts表。 在本表的contact_id列存储的是手机中联系人所相应的ID。通过上面的图能够知道,在手机中有两个联系人。 接下来看一下data表。 在本表中。我们最关心的有三列mimetype_id、raw_contact_id和data1。当中mimetype_id是mimetype表的主键ID;相应的raw_contact_id就是raw_contact的contact_id列了。 那么data1列代表的什么呢? 你猜的不错,就是我们联系人的数据。横向来看,raw_contact_id同样的行中data1列数据组成了一个联系人的数据。 在看一下mimetypes表的情况吧。 也是比較简单。不同的mimetype内容代表的不同数据类型。比方:电话号、姓名、Email等。 看起来非常麻烦的样子,貌似还须要讲data表和mimetypes表联合查询才干够。 可是实际上不用这么麻烦,Google工程师已经为我们准备了view_data的视图,已经将data和mimetypes两张表的数据联结起来了。 我们赶紧看看里面的内容吧。 了解视图结构后,我们通过contact_id查询一下,就能够得到数据的内容和内容类型了。 分析完联系人的表,接下来就是怎样使用内容解析者去查询了,跟之前一样。依然要知道主机名和路径。 跟着我一起看一下源代码,这次联系人应用内容提供者的路径为android4.4\packages\providers\ContactsProvider。打开清单文件,能够看到例如以下信息: <provider android:name="ContactsProvider2" android:authorities="contacts;com.android.contacts" android:label="@string/provider_label" android:multiprocess="false" android:exported="true" android:readPermission="android.permission.READ_CONTACTS" android:writePermission="android.permission.WRITE_CONTACTS"> </provider> 主机名是:com.andriod.contacts,记住别忘记加入读联系人和写联系人的权限。 再打开src\com\android\providers\contacts\ContactsProvider2.java文件,看一下路径是什么。 static { // Contacts URI matching table matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); ... ... matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); ... ... } 能够得知,查看raw_contacts的路径就是raw_contacts,查看data表的路径就是data。 该准备的东西都准备完成了。那么就进入到代码的步骤吧。 ① 在raw_contacts表中查询出来联系人的ID集合 ② 以联系人ID为过滤条件,在view_data视图中,查找mimetype和data1 下面是代码: // 在raw_contacts表中查询出来联系人的ID集合 Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts"); Uri viewDataUri = Uri.parse("content://com.android.contacts/data"); Cursor rawContactsCursor = getContentResolver().query(rawContactsUri, null, null, null, null); if (rawContactsCursor != null) { while (rawContactsCursor.moveToNext()) { int columnIndex = rawContactsCursor.getColumnIndex("contact_id"); String contact_id = rawContactsCursor.getString(columnIndex); // System.out.println("联系人ID:" + contact_id); // 以联系人ID为过滤条件。在view_data视图中,查找mimetype和data1 Cursor viewDataCursor = getContentResolver().query(viewDataUri, new String[] { "mimetype", "data1" }, "contact_id=?", new String[] { contact_id }, null); if (viewDataCursor != null) { while (viewDataCursor.moveToNext()) { String mimetype = viewDataCursor.getString(0); String data1 = viewDataCursor.getString(1); if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) { System.out.println("联系人ID:" + contact_id + ",电话:" + data1); } else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) { System.out.println("联系人ID:" + contact_id + ",email:" + data1); } else if ("vnd.android.cursor.item/name".equals(mimetype)) { System.out.println("联系人ID:" + contact_id + ",联系人姓名:" + data1); } } viewDataCursor.close(); } } rawContactsCursor.close(); } 利用内容提供者插入联系人 插入联系人分为下面几步: ①手动插入联系人ID;ID值为数据库中总条目数加1。 ②再依次向 data表中插入联系人数据。 总体的代码还是比較清晰地,请看下吧: String name = et_name.getText().toString().trim(); String phone = et_phone.getText().toString().trim(); int contact_id = 0; Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts"); Uri viewDataUri = Uri.parse("content://com.android.contacts/data"); // 手动插入联系人ID;ID值为数据库中总条目数加1。 Cursor rawContactsCursor = getContentResolver().query(rawContactsUri, null, null, null, null); if (rawContactsCursor != null) { int count = rawContactsCursor.getCount(); contact_id = count + 1; rawContactsCursor.close(); } // 插入联系人ID ContentValues values = new ContentValues(); values.put("contact_id", contact_id); getContentResolver().insert(rawContactsUri, values); // 再依次向`data`表中插入联系人数据。 ContentValues nameValues = new ContentValues(); nameValues.put("raw_contact_id", contact_id); nameValues.put("mimetype", "vnd.android.cursor.item/name"); nameValues.put("data1", name); getContentResolver().insert(viewDataUri, nameValues); ContentValues phoneValues = new ContentValues(); phoneValues.put("raw_contact_id", contact_id); phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2"); phoneValues.put("data1", phone); getContentResolver().insert(viewDataUri, phoneValues); 以上都是演示样例代码,假设要实际使用还须要做非常多非常多工作。 内容观察者的原理 ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理。它相似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时。便会触发它。 使用ContentObserver的情况主要有一下两者情况: ①须要频繁检測的数据库或者某个数据是否发生改变,假设使用线程去操作。非常不经济并且非常耗时 。 ②在用户不知晓的情况下对数据库做一些事件。比方:悄悄发送信息、拒绝接受短信黑名单等; 利用内容观察者监听系统应用数据库或者自己应用数据库的变化 这里就给出一个简单的样例吧。博主的学识还是太浅了,刚才浏览了网上一些人写的内容观察者的博客,认为自己会的东西还是太少了。小小总结一下。 当以后用到的时候再细致的总结。 使用观察者监听系统应用的变化 监听数据库的变化,主要使用到了ContentResler类中的registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)方法。 第一个參数是我们监视的Uri。第二个參数为true时会匹配全部以我们指定的Uri开头的地址,第三个參数就是我们的观察者了。 假设我们要监听系统短信数据库的变化,能够这么做: Uri uri = Uri.parse("content://sms"); getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); System.out.println("短信内容发生改变了"); } }); 已经知道了怎样监视一个Uri的变化后,监听我们自己应用数据库的变化,仅仅须要将Uri改动一下就能够了。可是,这里还差一步。当我们通过内容提供者去訪问已有数据后,还要通知一下,这样才干够让观察者接收到内容改变的消息。 这里就使用到了ContentReslover中的notifyChange(Uri uri, ContentObserver observer)方法。 // 提供给外部应用调用的查询方法 @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { int MATCH_CODE = MURI_MATCHER.match(uri); if (MATCH_CODE == QUERY_SUCCESS) { // 大喊一声,数据发生改变了 getContext().getContentResolver().notifyChange(uri, null); return db.query(ACCOUNT, projection, selection, selectionArgs, null, null, sortOrder); } return null; } 这两篇博客写的比較仓促,请多多包括了。 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5284454.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Linux基础之bash脚本进阶篇-循环语句(for,while,until)

20160909 补充break与continue的区别 什么是循环语句、死循环? 循环语句:将一段代码重复执行0、1或多次。 到底要重复运行多少次?以及我们如何设定循环语句的重复次数? 为了解决上面的问题于是就有了进入条件与退出条件。 进入条件:条件满足时进入循环。 退出条件:不符合条件退出循环。 一种特殊的循环:死循环 死循环:在编程中,一个无法靠自身的控制终止的循环称为"死循环"。死循环的出现有两种情况: 1、因程序需要刻意写的;2、因程序员的失误造成的。 第二种的死循环通常会造成比较严重的程序错误,甚至会因此而影响物理机。因此死循环的使用需要合理的设计。 实验环境CentOS7.2 本文重要的三个循环语句:for、while、until ……………………………………………………………………………………………………………………… for循环 for语句的使用格式: forNAME in LIST(列表);do 循环体 done 列表生成方式: (1)整数列表 {start..end} $(seq start [[step]end]) (2)glob /etc/rc.d/rc3.d/K* (3)命令 ……………………………………………………………………………………………………………………… 下面以一个例子看看for的具体作用 示例:计算1+2+...+10的值 1 2 3 4 5 6 7 8 9 #!/bin/bash #sumthevalueof"1+2+...+10" #authorchawan #date:20160906 declare -i sum =0 for x in {1..10}; do let sum +=$x done echo "Thesumis:$sum" 运行脚本0906-1结果如下 1 2 [root@dockerhmworks] #sh0906-1 The sum is:55 上面使用了第一种的整数列表中的第一种形式,这里如果是“1+2+...+n”这种形式那么{start..end}就不再适用,此时就只能使用$(seq start [[step]end])。下面再举一个例子说明 示例:计算“1+2+...+n”的值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/bin/bash #sum“1+2+...+n” #authorchawan #date:20160906 declare -i sum =0 #以交互的方式输入一个正整数 read -p "Pleaseinsetanumber:" num #判断输入的数是否为空,为空则提示并退出 [-z$num]&& echo "Pleaseinputanumber!" && exit 1 #判断输入的是否是正整数,若是则执行循环,若不是提示输入正整数并退出 if [[$num=~^[1-9][0-9]{0,}$]]; then for i in {1..$num}; do #foriin`seq1$num`;do let sum +=$i #sum=$[$sum+$i]这种方式也可以不过不够简练 done else echo "Error:pleaseinputapositiveinteger" && exit 2 fi #显示最后的和 echo "Thesumis:$sum" 下面执行该脚本 1 2 3 4 [root@dockerhmworks] #sh0906-2 Pleaseinsetanumber:8 0906-2:行14: let : sum +={1..8}:语法错误:期待操作数(错误符号是 "{1..8}" ) The sum is:0 该结果说明{start..end}形式不适用于有变量出现的情况,既然这个不行就来试试$(seq start [[step]end]) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/bin/bash #sum“1+2+...+n” #authorchawan #date:20160906 declare -i sum =0 #以交互的方式输入一个正整数 read -p "Pleaseinsetanumber:" num #判断输入的数是否为空,为空则提示并退出 [-z$num]&& echo "Pleaseinputanumber!" && exit 1 #判断输入的是否是正整数,若是则执行循环,若不是提示输入正整数并退出 if [[$num=~^[1-9][0-9]{0,}$]]; then for i in ` seq 1$num`; do let sum +=$i #sum=$[$sum+$i] done else echo "Error:pleaseinputapositiveinteger" && exit 2 fi #显示最后的和 echo "Thesumis:$sum" 执行该脚本 1 2 3 4 5 6 [root@dockerhmworks] #sh0906-2 Pleaseinsetanumber:10 The sum is:55 [root@dockerhmworks] #sh0906-2 Pleaseinsetanumber:100 The sum is:5050 该结果表明$(seq start [[step]end])适用性更好,因此一般建议使用它。 列表的glob与命令这两种就不再具体演示。大家感兴趣可以自己尝试下做个实验体会体会。 ……………………………………………………………………………………………………………………… while循环 while语句使用格式: whileCONDITION;do 循环体 done CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环; 因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正; 进入条件:CONDITION为true; 退出条件:CONDITION为false ……………………………………………………………………………………………………………………… 示例:计算1+2+...+10的值 1 2 3 4 5 6 7 8 9 10 11 12 #!/bin/bash #sumthevalueof"1+2+...+10"while #authorchawan #date:20160906 #为了严谨起见,事先声明变量sum及i为整数型 declare -i sum =0 declare -ii=1 while [$i- le 10]; do let sum +=$i #sum=$[$sum+$i]的简写形式 let i++ #不断修正变量体 done echo "Thesumis:$sum" 执行脚本,查看其是否正确执行 1 2 [root@dockerhmworks] #sh0906-3 The sum is:55 while与for的不同在于: 1、不需要列表,因此可以大大节省内存空间,因为for如果列表很大会占用较多内容空间,对系统性能会造成影响,所以此时while的优越性就显现出来,它不需要占用很多内存空间,只需要两个变量的空间及做加法即可。 2、while需要修正体来不断修正变量,最终在符合退出条件时结束循环。 ……………………………………………………………………………………………………………………… until循环 until语句使用格式: untilCONDITION;do 循环体 done CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“false”,则执行一次循环;直到条件测试状态为“true”终止循环; 因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正; 进入条件:CONDITION为false; 退出条件:CONDITION为true until的用法同while,唯一的区别在于进入循环与退出循环的条件相反。 以相同的例子来体会二者的区别 ……………………………………………………………………………………………………………………… 示例:计算1+2+...+10的值 1 2 3 4 5 6 7 8 9 10 11 #!/bin/bash #sumthevalueof"1+2+...+10"until #authorchawan #date:20160906 declare -i sum =0 declare -ii=1 until [$i-gt10]; do let sum +=$i let i++ done echo "Thesumis:$sum" 执行脚本,查看结果是否正确输出 1 2 [root@dockerhmworks] #sh0906-4 The sum is:55 通过比较while与until的唯一差别就在于判断条件。这两者其实算是同一种循环语句,只是进入及退出循环的条件正好相反。 循环控制语句(用于循环体中) 1、continue[N]:提前结束第N层的本轮循环,而直接进入下一轮判断; 其使用格式: whileCONDTIITON1;do CMD1 ... ifCONDITION2;then continue fi CMDn ... done ……………………………………………………………………………………………………………………… 示例:求100以内所有偶数之和;要求循环遍历100以内的所正整数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #!/bin/bash #求100以内所有偶数之和;要求循环遍历100以内的所正整数 #authorchawan #date:20160906 declare -ii=1 declare -i sum =0 while [$i- le 100]; do let i++ #如果为奇数则跳过该循环 if [$[${i}%2]- eq 1]; then continue fi let sum +=$i done echo "Theevennumbersum:$sum" 执行脚本,查看结果是否正确显示 1 2 [root@dockerhmworks] #sh0906-5 Theevennumber sum :2550 之前我写这个脚本时是这么写的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #!/bin/bash #求100以内所有偶数之和;要求循环遍历100以内的所正整数 #authorchawan #date:20160906 declare -ii=1 declare -i sum =0 while [$i- le 100]; do let sum +=$i #如果为奇数则跳过该循环,直接进入下一轮判断后面的程序不再执行 if [$[${i}%2]- eq 1]; then continue fi let i++ done echo "Theevennumbersum:$sum" 这就是我个人由于对continue的理解不够准确而造成的死循环。 由于continue是跳过其所在循环,直接进入下一轮判断,后面的语句都不再执行。 当时没注意这点所以错误地把i++放在后面,这就导致若i起始值为奇数那么它就一直在重复执行。 这里只要将let sum+=$i与let i++调换为止即可正确执行。 ……………………………………………………………………………………………………………………… 2、break[N]:提前结束循环; 其使用格式: whileCONDTIITON1;do CMD1 ... ifCONDITION2;then break fi CMDn ... done break的使用通常是与死循环同时出现的,下面来介绍如何创建死循环 创建死循环: whiletrue;do 循环体 done untilfalse;do 循环体 done ……………………………………………………………………………………………………………………… 示例:每隔3秒钟到系统上获取已经登录的用户的信息;如果docker登录了,则记录于日志中,并退出; 1 2 3 4 5 6 7 8 9 10 11 12 #!/bin/bash #每隔3秒钟到系统上获取已经登录的用户的信息;如果docker用户登录,则记录于日志中,并退出脚本 #authorchawan #date:20160906 while true ; do if who | grep "^docker\>" $> /dev/null ; then break fi sleep 3 echo "dockerisnotlogin" done echo "dockerloggedon." >> /tmp/user .log 运行脚本 1 2 3 4 5 6 7 [root@dockerhmworks] #sh0906-6 dockerisnotlogin dockerisnotlogin dockerisnotlogin dockerisnotlogin dockerisnotlogin dockerisnotlogin 为了验证该脚本,下面我们使用docker用户登陆 docker用户登陆后查看/tmp/user.log文件 ######################################################################################### break与continue语句的区别: break语句和continue语句都可以位于各种循环体内,用于控制当前的循环流程。但,break语句是直接退出当前的循环结构,转向执行循环体后面的语句;而continue语句则只是跳过当前循环体中continue语句后面的语句,转向当前循环体的起始位置,重新执行下一次循环,并没有退出当前的循环结构。 这是两者最本质的区别:break跳出当前循环,continue没有跳出当前循环。 循环语句的特殊用法(while及for) while循环的特殊用法(遍历文件的每一行): 其使用格式: whileread line;do 循环体 done< /PATH/FROM/SOMEFILE 依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line ……………………………………………………………………………………………………………………… 示例:找出其ID号为偶数的所有用户,显示其用户名及ID号; 1 2 3 4 5 6 7 8 9 10 #!/bin/bash #找出其ID号为偶数的所有用户,显示其用户名及ID号 #authorchawan #date:20160906 while read line; do if [$[` echo $line| cut -d:-f3`%2]- eq 0]; then echo -e-n "username:`echo$line|cut-d:-f1`\t" echo "uid:`echo$line|cut-d:-f3`" fi done < /etc/passwd 运行脚本 ……………………………………………………………………………………………………………………… for循环的特殊格式: for((控制变量初始化;条件判断表达式;控制变量的修正表达式));do 循环体 done 控制变量初始化:仅在运行到循环代码段时执行一次; 条件判断表达式:在什么条件下进行循环; 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断; 示例:求100以内所正整数之和 1 2 3 4 5 6 7 8 9 #!/bin/bash #求100以内所正整数之和 #authorchawan #date:20160906 declare -i sum =0 for ((i=1;i<=100;i++)); do let sum +=$i done echo "Thesumis:$sum" 运行脚本,查看结果是否正确 1 2 [root@dockerhmworks] #sh0906-8 The sum is:5050 for的这种格式减少了代码量,看着更简洁,不过其限制是只适用于有数字出现的循环,若是对某目录下的所有文件进行某种循环的执行就不适应了。 循环嵌套 在本文的最后再以一题体会下循环嵌套的神奇 示例:打印九九乘法表 1 2 3 4 5 6 7 8 9 10 #!/bin/bash #打印九九乘法表 #authorchawan #date:20160906 for ((j=1;j<=9;j++)); do for ((i=1;i<=j;i++)) do echo -e-n "${i}X${j}=$[$i*$j]\t" done echo done 我在刚刚接触循环嵌套时各种晕,循环嵌套不是没有目的的乱用,而是根据自己的需求有目的的使用,比如要打印99乘法表,开始要分析99乘法表的规律,分析后我们发现它横行是连续的,因此要用到一个循环(通常在遇到连续的内容都会用到循环)它的列也是连续的,因此又用到一个循环,而99乘法表又是由两个变化的量构成,综上我们就可以确定,需要使用两个变量,这两个变量分别要用到循环,而一个变量又受到另一个变量的限制,因此这个受限的变量就是被嵌套的主。问题分析到这里,我们解决这个问题要用到的工具都找出来了:两个变量,每个变量对应一个循环,同时一个变量受到另一个变量的限制,也就是说它需要在其循环内进行嵌套。 下面就是靠自己去使用工具解决问题了。我相信大家这点应该都不成问题,问题就分析到这里。 小结: 本文主要介绍什么是循环,死循环,bash常用的三种循环语句for、while、until及循环控制语句continue、break 在本文结尾又介绍了while的特殊用法(遍历文件中的每一行),for的c语言格式。 至于什么时候用for什么时候用while需要自己在实际写脚本中细细比较,鉴于本人也是新手,这里就算想细说也只能望洋兴叹。 本文转自 紫色的茶碗 51CTO博客,原文链接:http://blog.51cto.com/chawan/1847024,如需转载请自行联系原作者

优秀的个人博客,低调大师

Provisioning Services 7.6 入门到精通系列之二:基础架构环境

在阅读本博文之前强烈建议同学们提前了解Citrix XenDesktop和XenApp等产品,并对PVS相关产品概念架构有深入的理解。 1.1以下是在上一章节中规划的本次测试环境的配置清单(后续会根据高可用架构进行扩展) No. 主机名 服务器角色 操作系统 内存 IP地址 备注 1 CTXDC01 AD/DHCP/DNS Windows Server 2012 R2 2G 192.168.1.50 已部署 2 CTXLIC01 License Server Windows Server 2012 R2 2G 192.168.1.51 已部署 3 CTXDB01 MS SQL Windows Server 2012 R2 4G 192.168.1.52 已部署 4 CTXPVS01 PVS Windows Server 2012 R2 4G 192.168.1.53 1.2 准备好AD/DNS/DHCP、License Server、SQL Server和PVS Server共4台虚拟机后如下: 1.3根据以下博文完成AD/DNS的部署和配置 XenApp_XenDesktop_7.6实战篇之三:AD、DNS服务器规划及部署 http://stephen1991.blog.51cto.com/8959108/1659598 XenApp_XenDesktop_7.6实战篇之四:AD、DNS服务器高级配置 http://stephen1991.blog.51cto.com/8959108/1659609 XenApp_XenDesktop_7.6实战篇之五:组织单元、用户(组)、权限规划及配置 http://stephen1991.blog.51cto.com/8959108/1661048 1.4另外需额外创建配置以下域用户和组 类别 账户名称 作用及成员 备注 用户 CTXAdmin Citrix管理员 用户 SQLAdmin 数据库管理员 用户 SQLServices SQL服务账号 密码永不过期 用户 PVSServices PVS Stream Service和Soap Service账户 密码永不过期 用户组 CTXAdmins PVS场管理员组(成员:CTXAdmin、PVSServices) 具备PVS服务器本地管理员权限 用户组 SQLAdmins SQL Server管理员组(成员:CTXAdmins、SQLServices、SQLAdmin) 具备SQL服务器本地管理员权限 总体原则: PVS管理员ctxadmin和服务账号pvsservices必须对SQL具备管理员权限; PVS管理员和服务账号必须为PVS的本地管理员组成员; SQL管理员和服务账号必须为SQL服务器的本地管理员组成员 为PVS目标设备在AD创建计算机账户时还必须保证ctxadmin具备在AD创建计算机账户的权限,项目中如果允许可将ctxadmin加入到Domain Admins组中。 1.5根据以下博文完成DHCP的配置 XenApp_XenDesktop_7.6实战篇之六:DHCP服务器规划及部署 http://stephen1991.blog.51cto.com/8959108/1661053 1.6配置DHCP作用域选项66/67 1.7根据以下博文完成License Server的部署和配置 XenApp_XenDesktop_7.6实战篇之七:License Server规划及部署 http://stephen1991.blog.51cto.com/8959108/1661055 XenApp_XenDesktop_7.6实战篇之八:申请及导入许可证 http://stephen1991.blog.51cto.com/8959108/1661552 1.8根据以下博文完成SQL Server的部署和配置 XenApp_XenDesktop_7.6实战篇之九:SQL Server数据库服务器规划及部署 http://stephen1991.blog.51cto.com/8959108/1661577 在准备好AD/DNS/DHCP和数据库服务器,我们将在下一章节为大家分享PVS服务器的安装。 本文转自 Stephen_huang 51CTO博客,原文链接:http://blog.51cto.com/stephen1991/1683324,如需转载请自行联系原作者

优秀的个人博客,低调大师

菜鸟学Linux 第001天笔记 基础理论知识

主要学习的知识: RHCE RH033 RH133 RH253 RHCA: RH401 RH423(LDAP)学习不多 RH442 RH436(集群) RHS333 MySQL 应用行业: 运维工程师、系统工程师、系统架构师、DBA 所有后期实验都是在VMware里操作,必须学会使用此虚拟机。 计算机体系结构和如何运作: 运算器 控制器 存储器 输入设备 输出设备 程序=指令+数据 硬件架构(cpu架构) ARM(只生产知识产权,设计芯片,不生产设备) X86 X86 64 or X64 安腾 (intel 收购的HP的cpu) alpha HP UltraSparc Sun Power IBM (世界上第一个生产双核心,四核心,六核心,八核心, 第一个生产出超4GHZ主频的CPU) M68000,M68K 摩托罗拉 PowerPC 苹果、IBM、摩托罗拉 全作生产 OS (operating system) Windows Linux Unix 以下为Unix 不同的厂商 HP-UX Solaris AIX SCO UNIX Unixware 等 OS/2 硬件软件分层图 计算机发展史 Linux 发展史 Linux 组织 GNU: GNU is Not Unix 提供Linux 源代码 GPL: General Public license 通用公共许可证 以下是发行商把源代码打包编译成可执行程序的Linux, 因为他们是开源的,软件可以随便下载使用,所以主要利润来源于服务,即如果使用操作系统出故障,自己处理不了,需要联系他们时,则需要收服务费,根据其需要的响应时间不同收费不同。 你懂得 RedHat SLS Debian SUSE RHEL Red Hat Enterprise Linux CentOS Community Enterprise Operating System CentOS 是RHEL的源代码再编译的产物 本文转自Winthcloud博客51CTO博客,原文链接http://blog.51cto.com/winthcloud/1850625如需转载请自行联系原作者 Winthcloud

优秀的个人博客,低调大师

Android基础:关于Dialog和Activity的style的深入理解

<!-- 微博 --> <style name= "weibosdk_ContentOverlay" parent= "android:style/Theme.Dialog" > <item name= "android:windowNoTitle" > true </item> 没有标题 <item name= "android:windowIsTranslucent" > true </item> 透明 <item name= "android:windowBackground" > @color /weibosdk_transparent</item> 窗口背景色 <item name= "android:windowAnimationStyle" > @android :style/Animation.Translucent</item> 重要,Dialog进出的显示动画 <item name= "android:windowContentOverlay" > @null </item> 是否有覆盖 <item name= "android:backgroundDimEnabled" > false </item> dialog的背景是否昏暗 </style> 以上是自定义Dialgog可以使用自定义样式: 关于<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>重要,Dialog进出的显示动画要特别注意,可以自定义Dialog进出的动画,但是item的名字必须和下面的一样,以确定Android系统能够认识出来。 <style name= "Animation.Translucent" > <item name= "windowEnterAnimation" > @anim /translucent_enter</item> <item name= "windowExitAnimation" > @anim /translucent_exit</item> </style> ---------------------------------------------- Activity 自定义样式: <style name= "ThemeActivity" > <item name= "android:windowAnimationStyle" > @style /AnimationActivity</item> <item name= "android:windowNoTitle" > true </item> <item name= "android:windowFullscreen" > true </item> <item name= "android:windowContentOverlay" > @null </item> <item name= "android:windowIsTranslucent" > true </item> </style> 同样的每个item对应的name不能变,以保证Android系统能够辨认出来。 <style name= "AnimationActivity" parent= "@android:style/Animation.Activity" > <item name= "android:activityOpenEnterAnimation" > @anim /slideinright</item> 第一次创建新Activity是调用的动画 <item name= "android:activityCloseExitAnimation" > @anim /slideoutright</item> 调用finish关闭该Activity是调用的动画 <item name= "android:activityOpenExitAnimation" > @anim /slideoutleft</item> activity还没有finish()下退出效果 <item name= "android:activityCloseEnterAnimation" > @anim /slideinleft</item> 上一个activity返回进入效果 </style> 本文转自demoblog博客园博客,原文链接http://www.cnblogs.com/0616--ataozhijia/archive/2012/12/12/2815224.html如需转载请自行联系原作者 demoblog

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册