首页 文章 精选 留言 我的

精选列表

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

基础入门学习Python爬虫必备的知识点!

关于Python有一句名言:不要重复造轮子。 但是问题有三个: 1、你不知道已经有哪些轮子已经造好了,哪个适合你用。有名有姓的的著名轮子就400多个,更别说没名没姓自己在制造中的轮子。 2、确实没重复造轮子,但是在重复制造汽车。包括好多大神写的好几百行代码,为的是解决一个Excel本身就有的成熟功能。 3、很多人是用来抓图,数据,抓点图片、视频、天气预报自娱自乐一下,然后呢?抓到大数据以后做什么用呢?比如某某啤酒卖的快,然后呢?比如某某电影票房多,然后呢? 在学习python中有任何困难不懂的可以加入我的python交流学习q u n:227-435-450,多多交流问题,互帮互助,里有不错的学习教程和开发工具。学习python有任何问题(学习方法,学习效率,如何就业),可以随时来咨询我。 我认为用Python应该能分析出来,这个现实的世界属于政治家,商业精英,艺术家,农民,而绝对不会属于Python程序员,纵使代码再精彩也没什么用。 以下是经过Python3.6.4调试通过的代码,与大家分享: 抓取知乎图片 听两个聊天机器人互相聊天(图灵、青云、小i) AI分析唐诗的作者是李白还是杜 彩票随机生成35选7 自动写检讨书 屏幕录相机 制作Gif动图 1、抓取知乎图片,只用30行代码: import re from selenium import webdriver import time import urllib.request driver = webdriver.Chrome() driver.maximize_window() driver.get("https://www.zhihu.com/question/29134042") i = 0 while i < 10: driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(2) try: driver.find_element_by_css_selector('button.QuestionMainAction').click() print("page" + str(i)) time.sleep(1) except: break result_raw = driver.page_source content_list = re.findall("img src="(.+?)" ", str(result_raw)) n = 0 while n < len(content_list): i = time.time() local = (r"%s.jpg" % (i)) urllib.request.urlretrieve(content_list[n], local) print("编号:" + str(i)) n = n + 1 2、没事闲的时候,听两个聊天机器人互相聊天: from time import sleep import requests s = input("请主人输入话题:") while True: resp = requests.post("http://www.tuling123.com/openapi/api",data={"key":"4fede3c4384846b9a7d0456a5e1e2943", "info": s, }) resp = resp.json() sleep(1) print('小鱼:', resp['text']) s = resp['text'] resp = requests.get("http://api.qingyunke.com/api.php", {'key': 'free', 'appid': 0, 'msg': s}) resp.encoding = 'utf8' resp = resp.json() sleep(1) print('菲菲:', resp['content']) 网上还有一个据说智商比较高的小i机器人,用爬虫的功能来实现一下: import urllib.request import re while True: x = input("主人:") x = urllib.parse.quote(x) link = urllib.request.urlopen( "http://nlp.xiaoi.com/robot/webrobot?&callback=__webrobot_processMsg&data=%7B%22sessionId%22%3A%22ff725c236e5245a3ac825b2dd88a7501%22%2C%22robotId%22%3A%22webbot%22%2C%22userId%22%3A%227cd29df3450745fbbdcf1a462e6c58e6%22%2C%22body%22%3A%7B%22content%22%3A%22" + x + "%22%7D%2C%22type%22%3A%22txt%22%7D") html_doc = link.read().decode() reply_list = re.findall(r'"content":"(.+?)\r\n"', html_doc) print("小i:" + reply_list[-1]) 3、分析唐诗的作者是李白还是杜甫: import jieba from nltk.classify import NaiveBayesClassifier # 需要提前把李白的诗收集一下,放在libai.txt文本中。 text1 = open(r"libai.txt", "rb").read() list1 = jieba.cut(text1) result1 = " ".join(list1) # 需要提前把杜甫的诗收集一下,放在dufu.txt文本中。 text2 = open(r"dufu.txt", "rb").read() list2 = jieba.cut(text2) result2 = " ".join(list2) # 数据准备 libai = result1 dufu = result2 # 特征提取 def word_feats(words): return dict([(word, True) for word in words]) libai_features = [(word_feats(lb), 'lb') for lb in libai] dufu_features = [(word_feats(df), 'df') for df in dufu] train_set = libai_features + dufu_features # 训练决策 classifier = NaiveBayesClassifier.train(train_set) # 分析测试 sentence = input("请输入一句你喜欢的诗:") print(" ") seg_list = jieba.cut(sentence) result1 = " ".join(seg_list) words = result1.split(" ") # 统计结果 lb = 0 df = 0 for word in words: classResult = classifier.classify(word_feats(word)) if classResult == 'lb': lb = lb + 1 if classResult == 'df': df = df + 1 # 呈现比例 x = float(str(float(lb) / len(words))) y = float(str(float(df) / len(words))) print('李白的可能性:%.2f%%' % (x * 100)) print('杜甫的可能性:%.2f%%' % (y * 100)) 4、彩票随机生成35选7: import random temp = [i + 1 for i in range(35)] random.shuffle(temp) i = 0 list = [] while i < 7: list.append(temp[i]) i = i + 1 list.sort() print('[0;31;;1m') print(*list[0:6], end="") print('[0;34;;1m', end=" ") print(list[-1]) 5、自动写检讨书: import random import xlrd ExcelFile = xlrd.open_workbook(r'test.xlsx') sheet = ExcelFile.sheet_by_name('Sheet1') i = [] x = input("请输入具体事件:") y = int(input("老师要求的字数:")) while len(str(i)) < y * 1.2: s = random.randint(1, 60) rows = sheet.row_values(s) i.append(*rows) print(" "*8+"检讨书"+" "+"老师:") print("我不应该" + str(x)+",", *i) print("再次请老师原谅!") 以下是样稿: 请输入具体事件:抽烟 老师要求的字数:200 检讨书 老师: 我不应该抽烟, 学校一开学就三令五申,一再强调校规校纪,提醒学生不要违反校规,可我却没有把学校和老师的话放在心上,没有重视老师说的话,没有重视学校颁布的重要事项,当成了耳旁风,这些都是不应该的。 同时也真诚地希望老师能继续关心和支持我,并却对我的问题酌情处理。 无论在学习还是在别的方面我都会用校规来严格要求自己,我会把握这次机会。 但事实证明,仅仅是热情投入、刻苦努力、钻研学业是不够的,还要有清醒的政治头脑、大局意识和纪律观念,否则就会在学习上迷失方向,使国家和学校受损失。 再次请老师原谅! 6、屏幕录相机,抓屏软件: from time import sleep from PIL import ImageGrab m = int(input("请输入想抓屏几分钟:")) m = m * 60 n = 1 while n < m: sleep(0.02) im = ImageGrab.grab() local = (r"%s.jpg" % (n)) im.save(local, 'jpeg') n = n + 1 7、制作Gif动图: from PIL import Image im = Image.open("1.jpg") images = [] images.append(Image.open('2.jpg')) images.append(Image.open('3.jpg')) im.save('gif.gif', save_all=True, append_images=images, loop=1, duration=1, comment=b"aaabb")

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

第三章 Java的基础程序设计结构

一个简单的 Java 应用程序 访问修饰符 public,private,protected main 方法必须时public修饰的,C#则不必须 数据类型 可以用16进制表示浮点数 可以用2,8,16进制表示整数 Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY,DOUBLE.NaN 分别表示正无穷,负无穷,不是数值; if(x==Double.NaN) 永不成立,可以使用Double.isNaN(x)判断 强烈建议不要在程序中使用char,除非必须,可以使用String替代 运算符 整数被0除会抛出异常,浮点数则会得到无穷大或NaN结果 最初的JVM计算浮点时规定必须截断,这样在不同类型机器上可以得到一致的结果,但后来这点被修改, JVM设计者允许中间结果采用扩展的精度. 但是经过strictfp修饰的方法/类必须截断. 使用strictfp的方式可能产生溢出, 但不属于什么大问题. Math.floorMod 是为了解决有关整数余数的问题,即计算机设计中负数的余数为负数导致的不方便 StrictMath类能提供比Math更精确,更可预测的结果 int x; x+=3.5; 是合法的,结果为(int)(x+3.5) 字符串 StringBuilder 和 StringBuffer 的API是一样的, 不同的是StringBuffer是线程安全的,但使用StringBuilder效率较高; 流程控制语句 for中检测两个浮点数需要格外小心,for ( double x = 0 ; x ! = 10 ; x + = 0.1 ) 可能永远不会结束, 因为0.1不能精确用二进制表示 Java允许有标签的break语句,对嵌套循环的跳出到开头可以使用此类语句 数组 Arrays.copyOf()方法用于数组拷贝,将原数组的每个元素拷贝到新数组中去,通常用于数组扩容

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

Java基础“多线程”-你想知道的都在这里

Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。 这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。 多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。 进程和线程 进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。 线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。 一个进程中至少有一个线程。 Java VM 启动的时候会有一个进程java.exe. 该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。 扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。 创建线程的第一种方式-继承Thread类 步骤: 定义类继承Thread。 复写Thread类中的run方法。 目的:将自定义代码存储在run方法。让线程运行。 调用线程的start方法, 该方法两个作用:启动线程,调用run方法。 public class ThreadDemo { public static void main(String[] args) { Demo d = new Demo();//创建好一个线程。 d.start();//开启线程并执行该线程的run方法。 for (int x = 0; x < 60; x++) System.out.println("Hello World!--" + x); } } class Demo extends Thread { @Override public void run() { for (int i = 0; i < 60; i++) { System.out.println("demo run----" + i); } } } threaddemo.png 发现运行结果每一次都不同。 因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。 明确一点,在某一个时刻,只能有一个程序在运行。(多核除外) cpu在做着快速的切换,以达到看上去是同时运行的效果。 我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。 这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。 为什么要覆盖run方法呢? Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。 线程的运行状态 线程状态图.png 练习:创建两个线程,和主线程交替运行 class Test extends Thread { Test(String name) { super(name); } public void run() { for (int x = 0; x < 60; x++) { System.out.println((Thread.currentThread() == this) + "..." + this.getName() + " run..." + x); } } } public class ThreadTest { public static void main(String[] args) { Test t1 = new Test("one---"); Test t2 = new Test("two+++"); t1.start(); t2.start(); for (int x = 0; x < 60; x++) { System.out.println("main....." + x); } } } 线程交替运行.png 线程都有自己默认的名称。 Thread-编号 该编号从0开始。 static Thread currentThread():获取当前线程对象。 getName(): 获取线程名称。 设置线程名称:setName或者构造函数。 创建线程的第二种方式-实现Runnable接口 /** * 需求:简单的卖票程序。 * 多个窗口同时买票。 */ public class TicketDemo { public static void main(String[] args){ Ticket t = new Ticket(); Thread t1 = new Thread(t);//窗口1 Thread t2 = new Thread(t);//窗口2 Thread t3 = new Thread(t);//窗口3 Thread t4 = new Thread(t);//窗口4 t1.start(); t2.start(); t3.start(); t4.start(); } } class Ticket implements Runnable { private int ticket = 500; @Override public void run() { while (ticket > 0) { System.out.println(Thread.currentThread().getName() + "----sale:" + ticket--); } } } 步骤: 定义类实现Runnable接口 覆盖Runnable接口中的run方法。 将线程要运行的代码存放在该run方法中。 通过Thread类建立线程对象。 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。 为什么要将Runnable接口的子类对象传递给Thread的构造函数。 因为,自定义的run方法所属的对象是Runnable接口的子类对象。 所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。 实现方式和继承方式有什么区别呢? 实现方式好处:避免了单继承的局限性。 在定义线程时,建立使用实现方式。 两种方式区别: 继承Thread:线程代码存放Thread子类run方法中。 实现Runnable,线程代码存在接口的子类的run方法。 多线程的安全问题 上面的买票程序,加入线程等待 try{Thread.sleep(10);}catch(Exception e){} 线程安全异常.png 可能会出现0,-1,-2号票,多线程的运行出现了安全问题。 问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完, 另一个线程参与进来执行。导致共享数据的错误。 解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。 多线程同步代码块 Java对于多线程的安全问题提供了专业的解决方式。 就是同步代码块。 synchronized(对象) { 需要被同步的代码 } 对象如同锁。持有锁的线程可以在同步中执行。 没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。 上面的买票问题加入同步代码块之后: /** * 需求:简单的卖票程序。 * 多个窗口同时买票。 */ public class TicketDemo { public static void main(String[] args){ Ticket t = new Ticket(); Thread t1 = new Thread(t);//窗口1 Thread t2 = new Thread(t);//窗口2 Thread t3 = new Thread(t);//窗口3 Thread t4 = new Thread(t);//窗口4 t1.start(); t2.start(); t3.start(); t4.start(); } } class Ticket implements Runnable { private int ticket = 500; Object obj = new Object(); @Override public void run() { while (true) { synchronized (obj){ if (ticket>0){ // try { // Thread.sleep(10); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(Thread.currentThread().getName() + "----sale:" + ticket--); } } } } } 线程同步代码块.png 同步的前提: 必须要有两个或者两个以上的线程。 必须是多个线程使用同一个锁。 必须保证同步中只能有一个线程在运行。 好处:解决了多线程的安全问题。 弊端:多个线程需要判断锁,较为消耗资源, 同步函数的锁是this 函数需要被对象调用。那么函数都有一个所属对象引用。就是this。 所以同步函数使用的锁是this。 通过该程序进行验证。 使用两个线程来买票。 一个线程在同步代码块中。 一个线程在同步函数中。 都在执行买票动作。 class Ticket implements Runnable { private int tick = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(this) { if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....code : "+ tick--); } } } } else while(true) show(); } public synchronized void show()//this { if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--); } } } class ThisLockDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exception e){} t.flag = false; t2.start(); } } 静态同步函数的锁是class对象 如果同步函数被静态修饰后,使用的锁是什么呢? 通过验证,发现不在是this。因为静态方法中也不可以定义this。 静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象。 类名.class 该对象的类型是Class 静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class class Ticket2 implements Runnable { private static int tick = 100; //Object obj = new Object(); boolean flag = true; public void run() { if (flag) { while (true) { synchronized (Ticket.class) { if (tick > 0) { try { Thread.sleep(10); } catch (Exception e) { } System.out.println(Thread.currentThread().getName() + "....code : " + tick--); } } } } else while (true) show(); } public static synchronized void show() { if (tick > 0) { try { Thread.sleep(10); } catch (Exception e) { } System.out.println(Thread.currentThread().getName() + "....show.... : " + tick--); } } } class StaticMethodDemo { public static void main(String[] args) { Ticket2 t = new Ticket2(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try { Thread.sleep(10); } catch (Exception e) { } t.flag = false; t2.start(); } } 死锁 同步中使用的锁不一样,就会造成死锁 class Test implements Runnable { private boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if (flag) { while (true) { synchronized (MyLock.locka) { System.out.println(Thread.currentThread().getName() + "...if locka "); synchronized (MyLock.lockb) { System.out.println(Thread.currentThread().getName() + "..if lockb"); } } } } else { while (true) { synchronized (MyLock.lockb) { System.out.println(Thread.currentThread().getName() + "..else lockb"); synchronized (MyLock.locka) { System.out.println(Thread.currentThread().getName() + ".....else locka"); } } } } } } class MyLock { static Object locka = new Object(); static Object lockb = new Object(); } class DeadLockTest { public static void main(String[] args) { Thread t1 = new Thread(new Test(true)); Thread t2 = new Thread(new Test(false)); t1.start(); t2.start(); } } 线程间通信 线程间通信.png 其实就是多个线程在操作同一个资源, 但是操作的动作不同。 class Res { private String name; private String sex; private boolean flag = false; public synchronized void set(String name, String sex) { if (flag) try { this.wait(); } catch (Exception e) { } this.name = name; this.sex = sex; flag = true; this.notify(); } public synchronized void out() { if (!flag) try { this.wait(); } catch (Exception e) { } System.out.println(name + "........" + sex); flag = false; this.notify(); } } class Input implements Runnable { private Res r; Input(Res r) { this.r = r; } public void run() { int x = 0; while (true) { if (x == 0) r.set("mike", "man"); else r.set("丽丽", "女女女女女"); x = (x + 1) % 2; } } } class Output implements Runnable { private Res r; Output(Res r) { this.r = r; } public void run() { while (true) { r.out(); } } } class InputOutputDemo2 { public static void main(String[] args) { Res r = new Res(); new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); } } 等待唤醒机制 wait: notify(); notifyAll(); 都使用在同步中,因为要对持有监视器(锁)的线程操作。 所以要使用在同步中,因为只有同步才具有锁。 为什么这些操作线程的方法要定义Object类中呢? 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁, 只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。 不可以对不同锁中的线程进行唤醒。 也就是说,等待和唤醒必须是同一个锁。 而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。 思考1:wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中? 这些方法存在与同步中。 使用这些方法时必须要标识所属的同步的锁。 锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。 思考2:wait(),sleep()有什么区别? wait():释放cpu执行权,释放锁。 sleep():释放cpu执行权,不释放锁 生产者消费者问题 方法一: class ProducerConsumerDemo { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } class Resource { private String name; private int count = 1; private boolean flag = false; // t1 t2 public synchronized void set(String name) { while (flag) try { this.wait(); } catch (Exception e) { }//t1(放弃资格) t2(获取资格) this.name = name + "--" + count++; System.out.println(Thread.currentThread().getName() + "...生产者.." + this.name); flag = true; this.notifyAll(); } // t3 t4 public synchronized void out() { while (!flag) try { wait(); } catch (Exception e) { }//t3(放弃资格) t4(放弃资格) System.out.println(Thread.currentThread().getName() + "...消费者........." + this.name); flag = false; this.notifyAll(); } } class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { res.set("+商品+"); } } } class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { res.out(); } } } 对于多个生产者和消费者。 为什么要定义while判断标记。 原因:让被唤醒的线程再一次判断标记。 为什么定义notifyAll, 因为需要唤醒对方线程。 方法二: JDK1.5 中提供了多线程升级解决方案。 将同步Synchronized替换成现实Lock操作。 将Object中的wait,notify notifyAll,替换了Condition对象。 该对象可以Lock锁 进行获取。 该示例中,实现了本方只唤醒对方操作。 Lock:替代了Synchronized lock unlock newCondition() Condition:替代了Object wait notify notifyAll await(); signal(); signalAll(); import java.util.concurrent.locks.*; class ProducerConsumerDemo2 { public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } class Resource { private String name; private int count = 1; private boolean flag = false; // t1 t2 private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while (flag) condition_pro.await();//t1,t2 this.name = name + "--" + count++; System.out.println(Thread.currentThread().getName() + "...生产者.." + this.name); flag = true; condition_con.signal(); } finally { lock.unlock();//释放锁的动作一定要执行。 } } // t3 t4 public void out() throws InterruptedException { lock.lock(); try { while (!flag) condition_con.await(); System.out.println(Thread.currentThread().getName() + "...消费者........." + this.name); flag = false; condition_pro.signal(); } finally { lock.unlock(); } } } class Producer implements Runnable { private Resource res; Producer(Resource res) { this.res = res; } public void run() { while (true) { try { res.set("+商品+"); } catch (InterruptedException e) { } } } } class Consumer implements Runnable { private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while (true) { try { res.out(); } catch (InterruptedException e) { } } } } 停止线程 如何停止线程? 只有一种,run方法结束。 开启多线程运行,运行代码通常是循环结构。 只要控制住循环,就可以让run方法结束,也就是线程结束。 定义循环结束标记 因为线程运行代码一般都是循环,只要控制了循环即 使用interrupt(中断)方法。 该方法是结束线程的冻结状态,使线程回到 运行状态中来。 注:stop方法已经过时不再使用。 线程类的其他方法 setPriority(int num) setDaemon(boolean b) join() 自定义线程名称 toString()

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

C++程序设计基础(3)条件语句和循环语句

注:读《程序员面试笔记》笔记总结 1.知识点 1.1条件语句 (1)if……;(2)if……else……;(3)if……else if……;(4)switch(){case ():break;case():break;default:}。 关于switch的两点说明,第一是case后面结束后必须加break,否则将在执行某个case之后的所有case语句都会执行,第二是default可以省略。 1.2循环语句 (1)for(init;condition of continue circular;variables update);(2)while(condition)。 关于while的一点说明:当while(1)时一般在内部会有break来终止程序结束,否则进入死循环。 2.面试题 2.1.不使用break的switch语句 公司年底给员工发一条关于年终奖的短信,奖品根据员工年度绩效考评结果而定,具体见下表,请编写一个函数,输入为员工年度考评的结果,输出为短信的内容,短信中需要罗列员工所获得的所有奖品。 考评结果 年终奖品 优秀 A 美国 或英国十日游,五千元超市卡,两千元亚马逊卡,一个月奖金 良好B 五千元超市卡,两千元亚马逊卡,一个月奖金 及格C 两千元亚马逊卡,一个月奖金 未达标D 一个月奖金 1 string getMessage(char mark) { 2 string message = ""; 3 switch (mark) { 4 case 'A'://注意此处使用单引号表示字符,双引号表示字符串 5 message.append("美国或英国十日游,"); 6 case 'B': 7 message.append("五千元超市卡,"); 8 case 'C': 9 message.append("两千元亚马逊卡,"); 10 case 'D': 11 message.append("一个月奖金"); 12 default: 13 break; 14 } 15 return message; 16 } 17 //注意#include<string>来重载cout,才能够输出string类型的数据 2.2.for循环的三要素 写出下面程序的输出结果: 1 bool foo(char c) { 2 cout << c; 3 return true; 4 } 5 int main(int argc, char *argv[]) { 6 int i = 0; 7 for (foo('A'); foo('B') && (i++ < 2); foo('C')) { 8 foo('D'); 9 } 10 getchar(); 11 return 0; 12 } 答案:ABDCBDCB 2.3巧打乘法口诀表 编写一个函数,接受一个整形参数n表示输出的规模。要求只用一重循环输出乘法口诀表的全部内容,并且程序中不能使用任何条件语句。 1 void print(int n) { 2 int row = 1, column = 1; 3 char flag[] = " \n";//当列数等于行数时为flag[1]换行 4 while (row<=n) 5 { 6 cout << row << " * " << column << " = " << row * column << flag[column / row]; 7 int tem = column % row + 1;//当列数等于行数时,tem跳回1 8 row = column / row + row;//当列数等于行数时,行数加一 9 column = tem; 10 } 11 } 总结:(1)列号的变化规律符合取模运算,这种不断回到起点的数字排列特征符合取模运算的性质; 下一项列号=当前列号%当前行号+1 (2)对于行号来说,当列号等于行号时,行号加1,当列号等于行号时,行号不变。行号的变化规律符合整数除法的性质,当被除数小于除数时结果为零,当二者相等时结果为1。 下一项行号=当前列号/当前行号+1

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

python爬虫零基础入门——反爬的简单说明

之前在《如何开始写你的第一个python脚本——简单爬虫入门!》中给大家分享了一下写一个爬虫脚本的基本步骤,今天继续分享给大家在初期遇到的一个很烦人的问题——反爬及处理办法! 我们的工具及库为:python3.6、pycharm、requests库 基本步骤:获取网页源代码——匹配需要的内容——提取并保存。 在这中间经常遇到这么几类问题: 脚本中获取的网页源代码和网页右键查看的源代码不同(编码格式的问题除外),或者返回400状态码 需要登录才能获取,不登录不能查看源代码,网页中也是需要登录才可以访问的 有验证码 开始可以获取内容,运行一段时间后报错(具体情况有:服务器拒绝连接,即ip被封等)一般为HTTPError 我们逐条看看 Headers的使用 某些网站反感爬虫的到访,于是直接拒绝所有爬虫的请求,或者返回其他的网页源码比如:连接频繁稍后在访问,或者直接返回403的状态码,比如抓取简书主页的时候出现下图 这是因为我们在访问网站服务器的时候,没有做任何的伪装,就相当于告诉服务器“我是个脚本”,那么服务器当然不客气的拒绝你了! 处理方法其实很简单,我们在代码中伪装自己是个浏览器就可以了,requests库提供了相应的方法,headers参数,我们重新请求简书主页,加入我的headers参数,在看看结果 这样就实现了网页源代码的获取,这里用到了User-Agent这个参数,它的作用就是告诉HTTP服务器, 客户端使用的操作系统和浏览器的名称和版本值,获取它也很简单,比如我用的火狐浏览器,打开网页后,用F12打开开发者工具,然后选择网络,当访问简书主页的时候,会出现很多的情请求,随便找一个点击一下,右边就会出现请求头了,如下图: 而这个请求头中的其他参数也很重要,具体我们在随后的讲解中慢慢解释 requests.session方法 在我们想抓取某些需要登录才可以访问的网页时,就需要带上cookie参数,这个参数在请求头中,它记录了我们的账号信息,具体实现的方法有2个,1就是加入header参数中或者独立写到requests中,代码为requests.get(url,cookie=cookie)。而requests库还提供了另外一个方法: session,自动保存cookies,可以设置请求参数,下次请求自动带上请求参数 session可以用来提供默认数据,函数参数级别的数据会和session级别的数据合并,如果key重复,函数参数级别的数据将覆盖session级别的数据。如果想取消session的某个参数,可以在传递一个相同key,value为None的dict. 也就是说,我们使用session提交cookie后,服务器如果对cookie有变动,那么session也会自动记录,非常方便,代码实现: s = requests.Session() r = s.get(url,cookie=cookie) print(r.text) 验证码的处理 对于一些简单的验证码,可以进行简单的识别,但是有些反人类的比如12306的验证码,要么直接程序中显示并手工验证,要么通过第三方的打码平台进行验证,当然这个是要收费的。 requests.proxies方法、time模块 我们经常会遇到,脚本可以正常运行,但是很快就出现了报错,远程服务器断开连接或者拒绝访问等等情况,这是因为好多网站都有设定访问速度、次数、流量之类的。 同时这里也希望大家控制住自己,不要多线程不限制的下载,那样对网站很不好的! 这种情况下,requests库提供了一个proxies的方法,就是指定ip代理的功能,它的格式是{”http”: “http://10.10.10.10:3128“}这样的,注意key值部分,一定要正确,否则会报错。 而不用代理的话,也可以在程序中人工加入休眠时间的方式来强制脚本不那么快的运行,这就需要用到time库了,比如每次请求间隔0.5秒:time.sleep(0.5),或者加上random库,这样:time.sleep(random.random()*2) 自动化测试工具 selenium 为什么要把selenium放到最后呢,因为用它可以解决大部分的反爬!是的,这个库就是这么厉害! 这里就不详细讲了,随后开个单篇,我们慢慢说!还是那句话,学习本身是一个漫长的过程,我们需要不断的练习来增强我们的学习兴趣,以及学到更扎实的知识!大家加油!

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

C++程序设计基础(1)程序的编译和执行

注:读《程序员面试笔记》笔记总结 1.编译执行过程 1.1预处理: (1)所有以#开头的代码都属于预处理的范畴:#include,#define,#ifdef(#ifndef,#endif),#other(其他宏指令) (2)处理预定义的宏:例如__DATA__,__FILE__(前后都是两个下划线) (3)用一个空格代替连续的注释 (4)处理三元符:例如将??=替换成#(针对很古老的键盘,现在一般较少出现) 1.2编译: 对预处理后的代码进行词法、语法、语义分析,生成汇编代码(.s) 1.3汇编: 将汇编代码生成机器指令,生成目标文件(.o) 1.4链接: 和其他的目标文件以及库文件生成可执行程序 2.面试题 2.1简述#include<>和#include" "的区别 答案:#include直接从编译器指定的路径进行搜索,找不到则报错; #include“ ”则先从程序所做目录进行搜索,然后再到编译器指定路径进行搜索,(自定义的此种方式合适),搜索不到报错。 2.2简述#和##在define中的作用 答案:宏定义中的#运算符将其后面的参数转换成字符串; 宏定义中的##运算符将其前后的参数进行字符串连接。 1 #define PRINTCUBE(x) cout<<"cube("<<#x<<")="<<(x)*(x)*(x)<<endl; 2 3 PRINTCUBE(5); 4 5 //output: 6 //cube(5)=125 7 8 #define LINK3(x,y,z) x##y##z 9 10 LINK3(3,5,0) 11 12 //output: 13 //"350" 2.3简述assert断言的概念 答案:assert用于程序的DEBUG版本中检测条件表达式,如果结果为假,则输出诊断信息并终止程序。 注意点:(1)assert是一个带参数的宏,不是一个函数; (2)在#include语句前加入#define NDEBUG则禁用assert宏(即含有assert的语句都会被忽略); (3)在RELEASE中assert会被忽略(即含有assert的语句都会被忽略); (4)一个assert最好只有一个条件判断语句; 1 //修改前 2 assert(grade>0 && grade<=6); 3 //修改后 4 assert(grade>0); 5 assert(grade<=6); (5)在assert中不要去修改变量的值,否则在RELEASE中被忽略掉,造成结果不同; 1 //修改前 2 assert(success++>60); 3 //修改后 4 assert(success>60); 5 success++; (6)对用户的参数输入判断时,使用if语句来参数合法性检测,不要用assert。

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

day19_java基础加强_动态代理+注解+类加载器

一、动态代理 1.1、代理模式 什么是代理模式及其作用? Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一。 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 优点: (1) 职责清晰,真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。 (2) 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了保护目标对象的作用。 (3) 高扩展性。 结构: 一个是你要访问的真正的对象(目标类),另一个是代理对象,真正对象(目标对象)与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。 其实装饰(包装)设计模式就是静态代理。 静态代理模式简单案例: KindWomen.java(接口) package com.itheima.demo;public interface KindWomen {public void throwEye();public void doSomething();} PJL.java(目标类1 实现 接口,并具体实现) package com.itheima.demo;public class PJL implements KindWomen {@Overridepublic void throwEye() { System.out.println("潘金莲抛媚眼"); }@Overridepublic void doSomething() { System.out.println("潘金莲XOXO"); }} YPX.java(目标类2 实现 接口,并具体实现) package com.itheima.demo;public class YPX implements KindWomen {@Overridepublic void throwEye() { System.out.println("阎婆惜抛媚眼"); }@Overridepublic void doSomething() { System.out.println("阎婆惜XOXO"); }} WP.java(代理类 也实现接口,但是空实现) package com.itheima.demo;public class WP implements KindWomen {private KindWomen kw;public WP(KindWomen kw) {this.kw = kw; }@Overridepublic void throwEye() { kw.throwEye(); }@Overridepublic void doSomething() { kw.doSomething(); }} XMQ.java(我) package com.itheima.demo;public class XMQ {public static void main(String[] args) { PJL pjl = new PJL(); YPX ypx = new YPX(); KindWomen wp1 = new WP(pjl); KindWomen wp2 = new WP(ypx); wp1.throwEye(); wp1.doSomething(); wp2.throwEye(); wp2.doSomething();} 1.2、动态代理 动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。 动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象。 动态代理生成技术: 1. 基于jdk提供一个Proxy类,可以直接给实现某接口的实现类直接生成代理对象。 2. 基于cglib (spring框架会学习) java.lang.reflect.Proxy; 该类可以直接生成一个代理对象。 Proxy类的方法: public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例。 仅能代理实现至少一个接口的类(即目标对象需要至少有一个接口)。 ClassLoader:类加载器。固定写法,和被代理类使用相同的类加载器即可。 Class[]:代理类要实现的接口。固定写法,和被代理类使用相同的接口即可。 InvocationHandler:策略(方案)设计模式的应用。如何去具体实现代理,由我们自己决定。 InvocationHandler接口中的invoke方法:调用代理类的任何方法,此方法都会执行。 Object invoke(Object proxy, Method method, Object[] args) Object proxy:代理对象本身的引用。一般用不着。 Method method:当前调用的方法。 Object[] args:当前方法用到的参数。 动态代理模式简单案例: KindWomen.java(接口) package com.itheima.demo;public interface KindWomen {public void throwEye(double money);public void doSomething(double money);} PJL.java(目标类1 实现 接口,并具体实现) package com.itheima.demo;public class PJL implements KindWomen {@Overridepublic void throwEye(double money) { System.out.println("潘金莲拿了" + money + "元钱,抛媚眼"); }@Overridepublic void doSomething(double money) { System.out.println("潘金莲拿了" + money + "元钱,XOXO"); }} XMQ.java(我) package com.itheima.demo;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class XMQ {public static void main(String[] args) {final KindWomen kw = new PJL(); // 真实对象(目标对象)// final YPX ypx = new YPX();// PJL pjl = new PJL();// YPX ypx = new YPX();// KindWomen wp1 = new WP(pjl);// KindWomen wp2 = new WP(ypx);// wp1.throwEye();// wp1.doSomething();// wp2.throwEye();// wp2.doSomething();// public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) // 返回一个指定接口的代理类实例。仅能代理实现至少一个接口的类(即目标对象至少有一个接口)。 KindWomen proxy = (KindWomen) Proxy.newProxyInstance(kw.getClass().getClassLoader(), kw.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理帮你做事情之前,可以做别的事情"); Object o = method.invoke(kw, new Object[] { (Double) args[0] / 2 }); // 这是真实对象执行的方法(做的事情) System.out.println("代理帮你完做事情之后,仍可以做别的事情");return o; } }); proxy.throwEye(5); proxy.doSomething(10); }} 静态/动态代理图解: 1.3、AOP(面向切面编程)编程思想(Spring框架中的核心思想之一) Spring框架中的核心思想包括: Dependency Injection(依赖注入) Inverse of Control(控制反转) Aspect Oriented Programming(面向切面编程) AOP编程思想解决的问题: 1、问题:业务的方法日后会很多,这样会有很多重复的代码。 2、问题:业务已经存在很多的方法,并没有考虑到事务的问题,现在要求加上。那么业务的重心就变了。 动态代理实现AOP示例代码:(转账功能) 完成业务的代码: package com.itheima.service.impl;import com.itheima.dao.AccountDao;import com.itheima.dao.impl.AccountDaoImpl;import com.itheima.domain.Account;import com.itheima.service.AccountService;public class AccountServiceImpl implements AccountService {@Override // 运用AOP思想,转账功能就是转账功能,不要加其他的东西,比如事务控制、日志、权限控制等,这样代码健壮性好,优美。public void transfer(String fromname, String toname, double money) throws Exception {// ad.updateAccount(fromname, toname, money); AccountDao ad = new AccountDaoImpl();// 分别得到转出和转入账户对象 Account fromAccount = ad.findAccountByName(fromname); Account toAccount = ad.findAccountByName(toname);// 修改账户各自的金额 fromAccount.setMoney(fromAccount.getMoney() - money); toAccount.setMoney(toAccount.getMoney() + money);// 完成转账操作 ad.updateAccout(fromAccount);// int i = 10 / 0; ad.updateAccout(toAccount); }}/*package com.itheima.service.impl;import java.sql.Connection;import java.sql.SQLException;import com.itheima.dao.AccountDao;import com.itheima.dao.impl.AccountDaoImpl;import com.itheima.domain.Account;import com.itheima.service.AccountService;import com.itheima.util.C3P0Util;import com.itheima.util.ManagerThreadLocal;public class AccountServiceImpl implements AccountService { @Override public void transfer(String fromname, String toname, double money) { // ad.updateAccount(fromname, toname, money); AccountDao ad = new AccountDaoImpl(); try { ManagerThreadLocal.startTransacation(); // 开启事务 // 分别得到转出和转入账户对象 Account fromAccount = ad.findAccountByName(fromname); Account toAccount = ad.findAccountByName(toname); // 修改账户各自的金额 fromAccount.setMoney(fromAccount.getMoney() - money); toAccount.setMoney(toAccount.getMoney() + money); // 完成转账操作 ad.updateAccout(fromAccount); // int i = 10 / 0; ad.updateAccout(toAccount); ManagerThreadLocal.commit(); // 提交事务 } catch (Exception e) { try { ManagerThreadLocal.rollback(); // 回滚事务 } catch (Exception e1) { e1.printStackTrace(); } } finally { try { ManagerThreadLocal.close(); // 关闭 } catch (Exception e) { e.printStackTrace(); } } }}*/ 产生代理对象的工厂代码: package com.itheima.util;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import com.itheima.service.AccountService;import com.itheima.service.impl.AccountServiceImpl;public class ObjectFactory {// 该方法返回一个代理对象public static AccountService getAccountService() {final AccountService as = new AccountServiceImpl(); // 真实对象(目标对象) AccountService proxy = (AccountService) Proxy.newProxyInstance(as.getClass().getClassLoader(), as.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = null;try { ManagerThreadLocal.startTransacation(); // 开启事务// 执行的是真实对象的转账方法 invoke = method.invoke(as, args); ManagerThreadLocal.commit(); // 提交事务 } catch (Exception e) {try { ManagerThreadLocal.rollback(); // 回滚事务 } catch (Exception e1) { e1.printStackTrace(); } } finally {try { ManagerThreadLocal.close(); // 关闭 } catch (Exception e) { e.printStackTrace(); } }return invoke; } });return proxy; }} 测试类代码: package com.itheima.test;import com.itheima.service.AccountService;import com.itheima.util.ObjectFactory;public class TestTransfer {/** * @param args * @throws Exception */public static void main(String[] args) throws Exception {// AccountService as = new AccountServiceImpl();// as.transfer("aaa", "bbb", 100); AccountService as = ObjectFactory.getAccountService(); as.transfer("aaa", "bbb", 100); }}/*package com.itheima.test;import com.itheima.service.AccountService;import com.itheima.service.impl.AccountServiceImpl;import com.itheima.util.ObjectFactory;public class TestTransfer { public static void main(String[] args) throws Exception { AccountService as = new AccountServiceImpl(); as.transfer("aaa", "bbb", 100); }}*/ 二、注解 注解不是注释,注释是程序员写的,给程序员看的。注解给程序看,用于描述程序如何运行及在什么阶段来运行。现在在实际开发中,注解最大的功能是用于替换配置文件。 注解是jdk1.5的新特性。可以通过反射来让注解具有功能。注解格式: @Xxxx 2.1 JDK中的三个基本的注解: a. @Override 检查子类确实是覆盖了父类的方法。 b. @Deprecated 说明已经过时了。 c. @SuppressWarnings({ "unused", "deprecation", "rawtypes" }) 抑制程序中的警告。unused(变量未使用)、deprecation(过时)和rawtypes(泛型)表示警告的类型。{}数组。 d. @SuppressWarnings("all") all抑制所有警告。 示例代码如下: package com.itheima.demo1;import java.util.ArrayList;import java.util.Date;import java.util.List;public class Demo1 {// @SuppressWarnings({ "unused", "deprecation", "rawtypes" }) @SuppressWarnings("all")public void ff() {int i = 0; System.out.println("abc"); List list = new ArrayList(); System.out.println(new Date().toLocaleString()); }public void HaHa() { }}class Demo2 extends Demo1 {@Overridepublic void ff() { }@Deprecatedpublic void HaHaHa() { System.out.println(new Date().toLocaleString()); }} 2.2 自定义注解的语法(注解的肉体) 研究一下注解的本质: 声明一个注解(或者创建一个注解类): @interface 注解名{…} public @interface MyAnnotation {} 通过反编译可知,注解它的本质就是一个接口,这个接口需要继承 Annotation接口。但是不能按照下述的代码格式写,需要按照上述代码格式写。 public interface MyAnnotation extends java.lang.annotation.Annotation {...} 分析注解类中的成员: 注解本质上就是接口,我们知道接口中可以有属性和方法。 属性:public static final int age; 方法:public abstract void show(); 但是在注解中也可以有属性,也可以有方法。但是,注解中一般不使用属性。 在注解的开发中,我们只写方法。 我们管注解中的方法,叫做注解的属性。 在注解中我们管方法的返回值叫做注解的类型。 注解定义属性的格式 : 例如:int age(); 关于注解的属性类型可以有哪些? 1. 基本类型 2. String 3. 枚举类型 4. 注解类型 5. Class类型 6. 以上类型的一维数组类型 注解:就是在你的程序代码中的某个位置加了一个标记而已。 示例代码如下图所示: 2.3 注解的反射(注解的灵魂) 模拟 Junit 的 @Test 方法 a、反射注解类 java.lang.reflect.AnnotatedElement; < T extends Annotation > T getAnnotation(Class< T > annotationType) 得到指定类型的注解引用。没有,返回null。 Annotation[] getAnnotations() 得到所有的注解,包含从父类继承下来的。 Annotation[] getDeclaredAnnotations() 得到自己身上的注解。 boolean isAnnotationPresent(Class< ? extends Annotation > annotationType) 判断指定的注解有没有。 Class、Method、Field、Constructor等实现了AnnotatedElement接口。 例如: Class.isAnnotationPresent(MyTest.class); 判断类上面有没有@MyTest注解。 Method.isAnnotationPresent(MyTest.class); 判断方法上面有没有@MyTest注解。 b、反射注解中的属性 如下图元注解图片中所示: 2.4 元注解 a、自定义注解的存活范围(生命周期):默认是CLASS。 什么是 元注解? 答:只能用在注解类上的注解叫做元注解。(即:用于 修饰注解的注解) @Retention 作用:改变自定义注解的存活范围。 RetentionPolicy SOURCE CLASS RUNTIME 例如:@Retention(RetentionPolicy.RUNTIME) @Target 作用:指定该注解能用在什么地方。 ElementType TYPE METHOD FIELD ANNOTATION_TYPE 例如:@Target({ ElementType.METHOD, ElementType.TYPE }) @Documented 作用:使用了@MyTest的注解的类,如果@MyTest注解类上面有@Documented注解,那么使用了@MyTest的注解的类的API文档中会出现@MyTest的身影。 @Inherited 作用:说明使用了该注解的类的子类可以继续使用该注解。 示例代码如下图所示: 三、简单介绍Servlet3.0中的几个注解 增加对注解的支持。 Servlet3.0 要求:Tomcat7+ JDK6.0+ Servlet3.0:web.xml已经不是必须的了。替代它的就是注解。 四、类加载器 1、作用:类加载器负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class。 2、JVM中的类加载器:(当 JVM 启动时,会形成由三个类加载器组成的初始类加载器层次结构: ) BootStrap:是老大。类加载器的祖先。 打印它会得到null。 负责加载 JRE/lib/rt.jar(JDK中绝大部分的类) ExtClassLoader: 负责加载 JRE/lib/ext/*.jar AppClassLoader: 负责加载在 classpath环境变量中的所有类 类加载器之间的父子关系图和管辖范围图 3、父类委托机制 示例代码: package com.itheima;import javax.xml.crypto.dsig.keyinfo.KeyName;public class TestClassLoader {public static void main(String[] args) {// BootStrap:是老大。类加载器的祖先。 打印它会得到null。负责加载 JRE/lib/rt.jar(JDK中绝大部分的类) ClassLoader cl = KeyName.class.getClassLoader(); System.out.println(cl); // null// System.out.println(cl.getClass().getName()); // java.lang.NullPointerException// ExtClassLoader: 负责加载 JRE/lib/ext/*.jar // 没有找着可以测试的类,因为该目录下需要导入源码包,就没有测试啦!但是效果同AppClassLoader。// AppClassLoader: 负责加载在 classpath环境变量中的所有类 ClassLoader cl1 = Student.class.getClassLoader(); System.out.println(cl1); // sun.misc.Launcher$AppClassLoader@73d16e93 System.out.println(cl1.getClass().getName()); // sun.misc.Launcher$AppClassLoader }} 示例图解01: 示例图解02: 我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

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

用户登录
用户注册