精华内容
下载资源
问答
  • 不和外界接触的人
    千次阅读 多人点赞
    2019-06-18 10:11:05

     

     

    智能的人类

            人类在外界的影响下进化,又凭借自己的意志来影响外界。
            一亿多年前体重是人类上百倍的恐龙虽然称霸了地球,但它们也仅仅是“低级动物”,并没有任何迹象标明恐龙发展出了高级智能。而人类则不断通过基因突变来进化自身的组织,使得自身能够更加充分与外界接触并由此产生刺激,比如在触觉、视觉、听觉、嗅觉等等方面。更重要的是大脑还具有记忆功能,从而使得人类在与外界环境的接触中知道了“自我”和“外界”,明确了人类个体的各部分与外界的物理边界。
            通过外界的各种刺激,人类大脑不断得到加强,脑容量也越来越大。大脑里面的神经网络变得越来越复杂,其复杂程度甚至比宇宙还复杂。大量的复杂神经网络通过互相通过突触连接在一起,从而才有条件产生了高级智能。

    生命的起源

            在生命刚开始时,没有什么大脑,甚至连神经都没有。远古时期地球没有任何生命,直到后来海洋里面出现核糖核酸(RNA)和蛋白质,从今天来看这些根本不像生命的物质,却是生命最原始的形态;

    更多相关内容
  • Java AWT/Swing实现规则窗体控件

    千次阅读 多人点赞 2019-05-09 05:27:28
    由于是自学,又是大专,没有科班的基础,所以不是很care算法数据结构,因为Java可以快速作出一个肉眼可以看到的UI,所以我选择了Java而不是C/C++,同时由于MFC这些微软的系统强相关,也就是说,同时放弃了VC++。...

    Oracle裁员,关注了下Oracle,但依旧并不喜欢这家公司,一直觉得它经营不好Java。就好像Microsoft经营不好Linux一样(很奇怪,但总觉得会有这么一天!) 不写Java已经十余年了,但最近还是想起一些点滴。花了一个半的夜晚,完成了此文。

    本文献给为我们送雨伞而把皮鞋?湿了的猛人。


    终于有机会重写这个话题了。我承诺读完本文,对Java如何实现不规则控件将会有非常清晰的认知。

    什么是自省?作为一个做技术的工程师,在以往学习和工作的过程中肯定曾经遇到过超级多的问题,其中有一些是棘手的,很难解决的,最终不了了之的问题。过了些时日以后,重新审视,看看以往的这些疑难问题现在是不是可以解决了,这就是一种自省的态度。即便是对于已经解决的问题,以及已经掌握的理论,重新审视看有没有更优的解法,有没有新的思想,这很必要。

    缘由

    2003年是我接触Java的第一年,2004年是我接触Java的第二年。

    由于是自学Java,又是大专,没有科班的基础,所以最初不是很care算法和数据结构,因为Java可以快速作出一个肉眼可以看到的GUI,所以我选择了Java而不是C/C++,同时由于MFC这些和微软的系统强相关,也就是说,同时放弃了VC++。

    但是直到2006年我都被一个问题所困扰,即:
    如何用Java实现一个不规则的窗体或者控件?

    之所以有这个问题,是因为我那时觉得像豪杰超级解霸这种播放器的 换肤 功能非常牛逼,比较有趣,如果说做GUI,当然不能少了这个。让人惊奇的是,一个播放器界面竟然可以是一个如下般非规则的样式:
    在这里插入图片描述
    这太帅了!我也想用Java做。

    但是Java的界面只能是那种四四方方的样子, 如何能把这种四四方方的界面裁剪成类似上面的样子 ,这是我进入这个这个行业以来 第一个要解决的问题。

    我当时使用的Java SDK版本是J2sdk 1.4.2版本,经典版本。

    2006年12月Java 1.6发布之前,网上根本搜不到答案,我自己也是有时间就折腾,几乎把Swing/AWT的API都撸遍了,也没有结果。最终,我是通过Eclipse的SWT解决了问题。

    Eclipse的SWT让很多有同样需求的人眼前一亮。我的第一份工作就是基于SWT开发的。

    是的Eclipse SWT有可以切割Java窗体和控件的API,具体例子我就不说了,网上一搜一大片。问题是,我想用标准的J2SE来做这些啊!

    后来,我是通过JNI的方式,调用自己写的本地C/C++库来完成切割窗体的。我也是因为要写这个本地C代码,从而 顺便 开始学习C语言编程。

    这种功能用本地代码写是很容易的,比如在微软的Windows系统,就可以用Windows API来做,而在Linux系统,则可以用基于X11的Gnome,KDE来完成,毕竟本地的GUI库必然要支持这些功能。

    然而Java作为其承诺的 一次编写,到处运行 的跨平台语言,不可能用同一个接口去兼容不同操作系统平台的不同GUI效果,所以Java也就根本就没有提供这样的功能。

    Java的公共API只能完成所有操作系统平台都支持的操作,并且还要保证达到同样的效果,至少不能差太多。我们知道Windows和UNIX/Linux的X11完全就不是一个东西,甚至都不是一类东西…

    Java实现不规则控件这件事

    这里还需要再PS一下。

    关于Java实现不规则控件这件事,很多人纠结过,实际上Java作为承诺的跨平台语言,它的优势根本就不在开发GUI程序,GUI这种是严重依赖本地系统的。

    虽然Eclipse的SWT曾经给人眼前一亮的的感觉,但它依然不是万金油。

    SWT不需要显式的进行JNI操作,不需要引入额外的包,处在集成开发环境Eclipse本身,直接拿来就能用。但是它只是将JNI隐藏了。说白了,SWT之所以可以做出和本地系统几乎一样的GUI控件,它所做的就是 将Win32 API,X11 API这种本地API封装成了Java的API ,是的,说白了就是一层封装,没什么大不了的。

    在Java SE 1.6之前,Java AWT/Swing要想做不规则控件,需要你自己去折腾JNI,而SWT替你把这一切封装好了,这才是它的唯一优势。

    这不,Java SE 1.6出来后,SWT的优势就不在了。因为它在Java内部做了同样的事情。


    使用Java SE 1.6如何实现不规则窗口

    到了2006年12月份,Sun放出了Java SE 1.6,带来了福音!

    Java SE 1.6提供的 com.sun.awt.AWTUtilities 和Eclipse SWT一样,封装了JNI操作,让程序员可以直接使用,就像不知道JNI这回事一样。

    在这之后,当我们再次搜索 如何用Java实现不规则窗体 这个话题时,答案就有了,但是基本都是同一个答案:
    通过com.sun.awt.AWTUtilities提供的方法来完成!

    比如:

    com.sun.awt.AWTUtilities.setWindowShape(Window window, Shape shape);
    

    只需要初始化一个Shape对象,就能实现一个任意形状的窗口,我以圆形窗口为例:

    import java.awt.*;
    import javax.swing.*;
    import java.awt.geom.Ellipse2D;
    
    public class CircleFrame extends JFrame {
    	public CircleFrame () {
    		super("Triangle Frame");
    		setSize(500,500);
    		setUndecorated(true);
    	}
    
        public static void main(String[] args) {
    	CircleFrame frame = new CircleFrame();
    	frame.setVisible(true);
    	com.sun.awt.AWTUtilities.setWindowShape(frame, new  Ellipse2D.Double(0, 0, 500, 500));
        }
    
    }
    

    效果如下:
    在这里插入图片描述
    但是这明显不是我想要的,折腾了小两年,最后新版本提供了一行代码搞定,感觉受到了伤害。并且,在编译CircleFrame的时候,提示如下:

    root@name-VirtualBox:~# javac CircleFrame.java
    CircleFrame.java:16: warning: AWTUtilities is internal proprietary API and may be removed in a future release
    	com.sun.awt.AWTUtilities.setWindowShape(frame, new  Ellipse2D.Double(0, 0, 500, 500));
    	           ^
    1 warning
    

    但这种API是完全无法把控的,明显这种API使用JNI的方式实现特定的功能,严重依赖了平台,并且API本身提供方拥有最终解释权,换句话说,使用这种API是危险⚠️的,搞不好哪天就废弃或者改变了!毕竟com.sun的包嘛…不稳定,现如今这公司都不在了,唏嘘。


    正确的做法,当然是 不依赖API,所有事情自己做了。

    Java AWT 和 Java Swing


    当初在学习Java的时候,了解到Java提供了两种GUI API:

    • Java AWT
    • Java Swing

    我当时特意了解到这两者的本质不同:

    • Java AWT
      调用操作系统GUI平台原生的操作来生成控件,换句话说,AWT的容器,控件只是操作系统GUI容器,控件在JVM里面的一个影子,AWT操作的是系统原生的容器,控件,它们称作AWT组件的 本地同位体
      优势:效率高。
      劣势:依赖底层,不同系统的观感会不同。
    • Java Swing
      除了顶层容器,其它的控件都是不依赖底层操作系统GUI平台的,换句话说,Swing的容器和控件是JVM自己画出来的。
      优势:跨平台,因为画法是一样的。
      劣势:效率低,慢。

    不管怎样,本文将用上述AWT和Swing分别采用的两种方法,即调用底层的GUI操作以及自己画,来实现不规则的窗体和控件:

    • 不规则窗体将实现一个三角形的窗体。
    • 不规则控件将实现一个三角形按钮安装在上述三角形窗体中。

    Java AWT实现不规则控件

    先看AWT的Frame如何来做。先看Java代码:

    import java.awt.*;
    import java.awt.event.*;
    public class AWTDemo extends Frame {
    
    	// 三角形按钮btn
    	Button btn;
    	//本地方法,用来将窗口和按钮切割成三角形
    	private native void cutWindow(String title);
    	static {
    		System.loadLibrary("cutWindow");
    	}
    
    	public AWTDemo(String title, String btn_title) {
    		super(title);
    		setSize(500,500);
    		// 果断去掉窗口上方的标题栏
    		setUndecorated(true);
    
    		// 生成一个四四方方的按钮对象
    		btn = new Button(btn_title);
    		// 按钮事件处理,第一次按下换个字,第二次按下退出
    		btn.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				if (e.getSource() instanceof Button) {
    					Button bu = (Button)e.getSource();
    					if (bu.getLabel().equals("AWT button"))
    						bu.setLabel("To Exit");
    					else
    						System.exit(0);
    
    				}
    			}
    		});
    		// 黄色按钮
    		btn.setBackground(Color.YELLOW);
    		add(btn);
    	}
    
    	public static void main(String args[]) {
    		String title = "abc";
    		String btnpeer = "sun-awt-X11-XButtonPeer";
    		String btn_title = "AWT button";
    		// 实例化一个Frame对象
    		AWTDemo frame = new AWTDemo(title, btn_title);
    		// 显示它
    		frame.setVisible(true);
    		try {
    			// 至此为止一切都是四四方方的
    			Thread.sleep(2000);
    			frame.cutWindow(title);
    			// 窗口成了三角形
    			Thread.sleep(2000);
    			frame.cutWindow(btnpeer);
    			// 按钮也成了三角形
    		} catch (Exception e) {
    		}
    	}
    }
    

    先看效果,再说JNI代码:
    在这里插入图片描述
    点击一下三角形的黄色按钮:
    在这里插入图片描述

    这是如何实现的呢?嗯,这是调用了本地方法cutWindow,要理解cutWindow的逻辑,这里简单说点X Window的东西,如果是在Windows平台做实验,那么就需要了解下Windows API了。

    X Window系统是一个超级复杂的C/S模式的GUI系统,其实它的架构是比较简单的,类似我们远程登录的Telnet/SSH这些。我来类比一下:

    • Telnet/SSH
      你在 负责输入输出显示的客户端 上用 键盘 敲入字符以及控制键,字符序列传输至Telnet/SSH服务器处理,然后服务器回复另一字符序列,Telnet/SSH客户端收到后解释它们,以便按照协议规范在终端 回显字符,最终生成一个CLI。
    • X window
      你在 负责输入/输出和显示的X服务器 上用 键盘,鼠标 执行一系列操作,这些操作被X服务器传输至X客户端处理,然后X客户端按照X协议规范回复数据序列,X服务器收到后解释它们,以便按照X协议规范决定 在X服务器的Display 显示器哪个像素绘制什么颜色,最终生成一个GUI。

    它们非常类似,简直是一个逻辑。唯一不同的是,X window貌似和Telnet/SSH的客户端/服务器是反着的。事实上理解起来很简单,毕竟X服务器就是用来显示的嘛。

    X Window系统封装了一系列的容器,控件,比如画布,按钮,复选框…X客户端可以以这些封装好的容器,控件为单位进行操作。

    深入的X window本文不谈,现在回到Java AWT程序。

    刚才说了,每一个AWT容器或者控件,都只是操作系统本地GUI的一个容器或者控件的影子,那么 如果我们想操作这个AWT对象,就要找到它的本地对象!

    我们用X系统的实现之一X11提供的 xwininfo 命令来探究一下内外。关于xwininfo,了解下面的就够了:

    0.你可以把display 理解成一个显示器加上一套鼠标/键盘的套件。
    1. X系统一个Display对象的所有窗体控件均按照Tree形式嵌套组织,比如一个Frame上的Button就是该Frame的child,这与Linux的进程组织非常类似。
    2. xwininfo可以枚举系统当前Display上的所有的窗体,并且给出其组织关系。

    简单修改一下代码,做一个 AWTDemo2.java ,去掉那些本地方法调用,仅仅保留主干:

    import java.awt.*;
    public class AWTDemo2 extends Frame {
    
    	Button btn;
    
    	public AWTDemo2(String title, String btn_title) {
    		super(title);
    		setSize(500,500);
    		setUndecorated(true);
    
    		btn = new Button(btn_title);
    		add(btn);
    	}
    
    	public static void main(String args[]) {
    		String title = "abc";
    		String btn_title = "AWT button";
    		AWTDemo2 frame = new AWTDemo2(title, btn_title);
    		frame.setVisible(true);
    	}
    }
    

    先执行 java AWTDemo2 打开AWT Frame界面,然后我们通过 xwininfo 看看能不能找到我们的AWT对象。

    root@name-VirtualBox:~# xwininfo -tree -root
    	...
               # 下面的Frame就是我们的AWT Frame
         0x1c00007 "abc": ("sun-awt-X11-XFramePeer" "AWTDemo2")  500x500+67+27  +67+27
            2 children:
            0x1c0001f "FocusProxy": ("Focus-Proxy-Window" "FocusProxy")  1x1+-1+-1  +66+26
            0x1c0001c "Content window": ("sun-awt-X11-XContentWindow" "AWTDemo2")  500x500+0+0  +67+27
               1 child:# 下面的这个child就是我们的AWT Button
               0x1c00020 "sun-awt-X11-XButtonPeer": ("sun-awt-X11-XButtonPeer" "AWTDemo")  500x500+0+0  +67+27
         ...
    

    果真是找到了:

    0x1c00007 "abc": ("sun-awt-X11-XFramePeer" "AWTDemo2")  500x500+67+27  +67+27
    0x1c00020 "sun-awt-X11-XButtonPeer": ("sun-awt-X11-XButtonPeer" "AWTDemo2")  500x500+0+0  +67+27
    

    Java代码里没有任何与外界的交互,但是X系统里还是找到了。所以说:
    Frame/Button这种AWT组件对于X系统是可见的,同样在Windows系统上,它也是可见的!

    如果我们换成Swing控件呢?相同的布局,只是将Frame换成JFrame,将Button换成JButton,如何呢?让我们试一下:

    import javax.swing.*;
    
    public class SwingDemo2 extends JFrame {
    
    	JButton btn;
    
    	public SwingDemo2(String title) {
    		super(title);
    		setSize(500,500);
    		setUndecorated(true);
    
    		btn = new JButton("Swing button");
    		add(btn);
    	}
    
    	public static void main(String args[]) {
    		String title = "abc";
    		SwingDemo2 demo = new SwingDemo2(title);
    		demo.setVisible(true);
    	}
    }
    

    用java SwingDemo2执行的同时,xwininfo的结果如何呢?看一下:

         0x2000007 "abc": ("sun-awt-X11-XFramePeer" "SwingDemo2")  500x500+67+27  +67+27
            2 children:
            0x200001f "FocusProxy": ("Focus-Proxy-Window" "FocusProxy")  1x1+-1+-1  +66+26
            0x200001c "Content window": ("sun-awt-X11-XContentWindow" "SwingDemo2")  500x500+0+0  +67+27
    

    Content window不再有Button这个child了!那么这个JButton到底在哪里呢?

    JButton对于X系统是不可见的,同样在Windows系统上,它也是不可见的!Java Swing除了顶层容器,其它都是自己在JVM里画大的,JVM系统外不可见!

    这下就清晰多了!我们通过xwininfo彻底理解了AWT和Swing到底区别在哪里了!


    是时候上JNI调用的本地代码了!这是用C写成的,基于X11编写。

    所谓的 本地代码 ,顾名思义就是跨平台解释执行的Java JVM之外的不受JVM控制的代码,脱离Java规范的约束 。这种支持在Java规范里叫做JNI。类似内联汇编对C语言的降维打击(内联汇编不受外部C语言规范的约束!)一样,本地代码也能对Java代码实施降维打击。所以如果你写了本地代码,你一定要知道你在干什么,通过Java的调试方法是无法知道本地代码的细节的!

    接下来,若要Java代码和本地代码对接起来,需要一个 接口 ,该接口就是通过 javah AWTDeom 生成的一个 AWTDemo.h 的C/C++头文件:

    #include <jni.h>
    
    JNIEXPORT void JNICALL Java_AWTDemo_cutWindow
      (JNIEnv *, jobject, jstring);
    

    接下来就是实现 Java_AWTDemo_cutWindow 函数了。

    JNI规范要求单独做一个动态连接库,在Linux系统,就是一个叫做 libAWTDemo.so 的动态库文件,注意,文件名一定要有 lib 前缀,因为Linux加载器就是这样加载库的。

    我下面直接给出带有注释的 cutWindow.c 文件:

    #include <X11/Xos.h>
    // 这个shape extension非常重要
    #include <X11/extensions/shape.h>
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include "AWTDemo.h"
    
    // 该函数执行根据名字查找组件句柄的逻辑,不解释,详情参见X11编程文档。
    // 如果是Windows系统,那么就是另一种方式获取组件的句柄了。
    // 注意:这个例子并没有借助使用AWT本地同位体的概念,所以需要手工自己查找
    Window findWindowByName(Display *dpy, Window parent, char *name)
    {
    	unsigned int num, i;
    	Window *subwindow, dummy;
    	Window result = 0;
    	char *title;
    
    	// 按照名称查找,如果名称匹配,就返回当前的组件。
    	XFetchName(dpy, parent, &title);
        	if (title && !strcmp(name, title)) {
    		return parent;
    	}
    
    	// 否则递归查找其所有的children
    	if (!XQueryTree(dpy, parent, &dummy, &dummy, &subwindow, &num))
    		return 0;
    
    	for (i = 0; i < num; i ++)  {
    		result = findWindowByName(dpy, subwindow[i], name);
    		if (result) {
    			goto free_and_ret;;
    		}
    	}
    
    free_and_ret:
    	if (subwindow)
    		XFree ((char *)subwindow);
    	return result;
    }
    
    JNIEXPORT void JNICALL Java_AWTDemo_cutWindow (JNIEnv *jenv, jobject o1, jstring title)
    {
        Window window;
        Display *dpy;
        Region region;
        XPoint p[3];
        XPoint pbtn[3];
    
       unsigned char *name = NULL;
       // 首先需要把Frame或者Button的title通过JNI传递到C/C++代码里
       name = (*jenv)->GetStringUTFChars(jenv, title, 0);
    
        dpy = XOpenDisplay(":0");
        if (!dpy) {
            exit(1);
        }
    
    	// 按照X11的API文档查找名字为name的容器或者控件,也就是做类似于xwininfo命令做的事情
    	// 这实际上是一个枚举所有组件的过程。
    	// 事实上,可以通过AWT本地同位体将window句柄通过参数传递过来的。为了不引入同位体的概念,暂时不考虑。
        window = findWindowByName(dpy, DefaultRootWindow(dpy), name);
        if (!window) {
            exit(1);
        }
    	// Frame的三角形外形三点定义
        p[0].x = 250; p[0].y = 125;
        p[1].x = 450; p[1].y = 425;
        p[2].x = 50; p[2].y = 425;
    	
    	// Button的三角形外形三点定义
        pbtn[0].x = 250; pbtn[0].y = 190;
        pbtn[1].x = 320; pbtn[1].y = 290;
        pbtn[2].x = 180; pbtn[2].y = 290;
    
        if (!strcmp(name, "abc")) { 
        	// Frame的区域
        	region = XPolygonRegion(p, 3, EvenOddRule);
        } else {
        	// Button的区域
        	region = XPolygonRegion(pbtn, 3, EvenOddRule);
        }
        // 设置组件的外形
        XShapeCombineRegion(dpy, window, ShapeBounding, 0, 0, region, ShapeSet);
    	// close该Display时会flush/repaint组件。
        XCloseDisplay(dpy);
    }
    

    代码写好了,接下来看看如何将其做成动态链接库。JNI的规范里对这个步骤也有说明,我下面直接给出:

    root@name-VirtualBox:~# gcc -fPIC -c -I"/usr/lib/jvm/java-8-openjdk-amd64/include" -I"/usr/lib/jvm/java-8-openjdk-amd64/include/linux" cutWindow.c -o cutWindow.o
    root@name-VirtualBox:~# gcc -shared -o libcutWindow.so cutWindow.o
    

    OK!现如今,该例子的AWTDemo.class运行所需的所有依赖都已经准备好了,我们希望JVM在当前路径下去加载 libcutWindow.so

    root@name-VirtualBox:~# javac AWTDemo.java
    root@name-VirtualBox:~# java -Djava.library.path=. AWTDemo
    

    执行起来就是上面图示的效果!

    本地代码是通过控件的Title来查找本地同位体的,如果是Windows平台,查找组件的操作要简单的多,只有有API可用:

    HWND FindWindowA(
      LPCSTR lpClassName,
      LPCSTR lpWindowName
    );
    

    详情参见:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-findwindowa
    【PS:我十多年前的不规则窗口版本就是在Windows平台做的,用的就是上面这个FindWindowA】

    事实上可以通过参数将本地同位体的控件句柄直接从Java代码传递到本地代码中的,这个后面再说。

    上述的本地代码动态库是基于X11实现的,我本来想用GTK,KDE来做例子,然而这些并不是原汁原味的,会引入很多额外的东西,比如看了GTK代码后,就会纠结于GTK是怎么回事…我们是在做Java不规则控件,而不是在学习GTK。所以越底层越好。

    在实现中,代码中使用了X11的Shape extension,这是一个扩展,并不包含在原生的X11中,基于它可以实现不规则的窗口和控件,它非常复杂,详细参见:
    https://en.wikipedia.org/wiki/Shape_extension
    https://www.x.org/releases/X11R7.7/doc/xextproto/shape.html
    本文不赘述,还是那句话,Java以外的,点到为止。

    AWT版本的自定义不规则组件的介绍就是这么多。接下来看看Swing的版本。


    Java Swing实现不规则控件

    前面说了,Java Swing除了顶层的容器,其它的控件组件都是自己画出来的,那么要实现不规则的JFrame,作为顶层容器的JFrame,由于其依然是映射到本地的真实窗口,所以依然是上面的JNI的方法去切割。

    重点是JButton的不规则化如何来做。换句话说,如何把它 画出来

    JButton在本地的GUI系统里根本就找不到,就像上面xwininfo展示的结果那样,怎么办?

    画一个就是了!

    如何来画呢?我还是直接给出完整的代码吧, SwingDemo.java 列如下:

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    
    // 从JButton派生一个子类,实现三角形JButton
    class triangleButton extends JButton {
    	// 此Button的三角形区域
    	Polygon triangle;
    	triangleButton(String title, int x[], int y[]) {
    		super(title);
    		// 根据参数初始化三角形区域
    		triangle = new Polygon(x, y, 3);
    		// 不显示按钮边框!完全由我们自己绘制的三角形来决定
    		setBorderPainted(false);
    		setContentAreaFilled(false);
    	}
    
    	// 重写paintComponent方法,区分按钮按下和释放时显示不同的颜色,显得逼真!
    	public void paintComponent(Graphics g) {
    		if (this.getModel().isPressed()) {
    			g.setColor(Color.BLACK);
    		} else {
    			g.setColor(Color.LIGHT_GRAY);
    		}
    		// 用不同的颜色画同一个三角形
    		// 如果能细化边缘凸凹高亮,那就更美观了!但是那样代码太长。
    		g.fillPolygon(triangle);
    		super.paintComponent(g);
    	}
    
    	// 重写contains,判断鼠标当前的焦点是不是属于该按钮的区域范围内。
    	// 这是Java Swing的创举,委托UI管理器来实现范围限定约束的托管!
    	public boolean contains(int x, int y) {
    		if (triangle.contains(x, y))
    			return true;
    		return false;
    	}
    }
    
    public class SwingDemo extends JFrame {
    	JButton btn;
    	// 定义按钮三角形的三点
    	int button_x[] = {250, 315, 185};
    	int button_y[] = {327, 227, 227};
    
    	// 用户切割JFrame的本地方法
    	private native void cutWindow(String title);
    	static {
    		System.loadLibrary("cutWindow");
    	}
    
    	public SwingDemo(String title) {
    		super(title);
    		setSize(500,500);
    		setUndecorated(true);
    
    		btn = new triangleButton("Swing button", button_x, button_y);
    		btn.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				if (e.getSource() instanceof triangleButton) {
    					triangleButton bu = (triangleButton)e.getSource();
    					if (bu.getText().equals("Swing button"))
    						bu.setText("To Exit");
    					else
    						System.exit(0);
    
    				}
    			}
    		});
    		add(btn);
    	}
    
    	public static void main(String args[]) {
    		String title = "abc";
    		SwingDemo demo = new SwingDemo(title);
    		demo.setVisible(true);
    		// 切割JFrame为三角形,同AWTDemo
    		demo.cutWindow(title);
    	}
    }
    

    当执行 java SwingDemo 时,展示一下效果:
    在这里插入图片描述
    点击一下试试看,点击的瞬间,三角形变成了黑色,这个太快了,没法截屏,但是松开鼠标后,按钮的字变了:在这里插入图片描述
    再点一下,如代码逻辑所示,退出。

    别看这是Swing画出来的,但 这是真正的三角形按钮,不仅仅是视觉上的,你只有点击那个小三角形区域,才会有效果,别的区域是不行的。

    Swing版本的不规则窗口和按钮总结下来就是:

    • Swing窗口依然采用JNI的方式在X11 API实现的动态库里进行切割;
    • Swing窗口上的按钮,自己编码绘制完成不规则化。

    纯Java的完整例子(?窗口,?按钮)

    能不能不用JNI?

    可以的。

    不用JNI实现窗口切割,不用说也能猜到原理,Java的工具包自己帮你JNI了呗。

    当我们已经理解了上述细节后,表示可以完全hold住java的api后,便可以自由使用一开始我并不提倡的Java自带的com.sun.awt.AWTUtilities了。

    com.sun.awt.AWTUtilities ,它就是用JNI实现窗口切割的。那么我便使用它直接来完成一个不规则窗口,不然我还要自己写本地代码,我又不想深入去学习X11。那么OK,我直接用AWTUtilities了!

    这个例子中,我使用一双大皮鞋图片作为窗口,一双小皮鞋图片作为按钮,窗口的形状是大皮鞋,按钮的形状是小皮鞋,皮鞋是不规则的,所以窗口和控件是不规则的。

    代码只有一个文件, SkinShoeDemo.java ,列如下:

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    import java.awt.image.*;
    import javax.imageio.ImageIO;
    import java.net.URL;
    import java.io.*;
    
    // 实现不规则的小皮鞋按钮
    class LittleSkinShoeButton extends JButton {
    	ImageIcon img;
    	BufferedImage imgpixe;
    	LittleSkinShoeButton(ImageIcon img, String icon){
    		super();
    		this.img = img;
    		setBorderPainted(false);
    		setContentAreaFilled(false);
    		setSize(img.getIconWidth(),img.getIconHeight());
    		try{
    			// 需要完整的图片像素来确定哪些像素属于皮鞋,哪些像素不属于皮鞋,这个涉及到“抠图”,后面会讲
    			imgpixe = ImageIO.read(SkinShoeDemo.class.getResource(icon));
    		} catch (Exception e){
    			System.exit(0);
    		}
    	}
    
    	// 当鼠标点击小皮鞋按钮“皮鞋区域”内部时,要展示出被点击的样子来,向下凹陷一下。
    	public void paintComponent(Graphics g){
    		if(this.getModel().isPressed()){
    			// 向下凹陷5个像素,向右平移5个像素,感觉像是被点击了。
    			g.drawImage(img.getImage(), 5, 5, this);
    		}else{
    			// 不被点击时,保持在原来的位置。
    			g.drawImage(img.getImage(),0,0,this);
    		}
    	}
    
    	// 重写contains方法。
    	public boolean contains(int x,int y){
    		int rgb,alpha;
    		try{
    			rgb = imgpixe.getRGB(x,y);
    			// 获取像素的alpha值,如果是被“抠去”的,就不属于皮鞋内部。
    			// 当初制作皮鞋图的时候,不是皮鞋范围的都“抠掉成透明”的了。
    			alpha = (rgb>>24) & 0xFF;
    			if(alpha != 0){
    				System.out.println("属于小皮鞋范围,点击有效:[" + x + "," + y );
    				return true;
    			}
    		}catch(ArrayIndexOutOfBoundsException e){
    		}
    		System.out.println("不属于小皮鞋范围,点击无效:[" + x + "," + y );
    		return false;
    	}
    }
    
    // 实现JFrame的背景图片,即一双大皮鞋。
    class SkinShoePanel extends JComponent {
        private Image image;
        public SkinShoePanel(Image image) {
            this.image = image;
        }
    	
    	// 重绘,也就是画大皮鞋
        protected void paintComponent(Graphics g) {
            g.drawImage(image, 0, 0, this);
        }
    }
    
    // 大皮鞋窗口主类
    public class SkinShoeDemo extends JFrame {
    
    	JButton btn;
    
    	private JPanel pixieimgPanel;
    	public SkinShoeDemo(BufferedImage img, ImageIcon btn_img, String icon) {
    		super("SkinShoe");
    		setSize(img.getWidth(), img.getHeight());
    
    		btn = new LittleSkinShoeButton(btn_img, icon);
    		btn.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				if (e.getSource() instanceof LittleSkinShoeButton) {
    					// TODO
    				}
    			}
    		});
    		this.setContentPane(new SkinShoePanel(img));
    		btn.setLocation(280, 280);
    		this.setUndecorated(true); // 这个必须调用
    		// 按钮添加在画布上。
    		this.getContentPane().add(btn);
    	}
    
    	public Shape getSkinshoeShape(BufferedImage pixieimg) {
    		Area pixie = new Area();
    		int width;
    		int height;
    		int x,y, temp; // temp起到了优化的作用,批量添加区域
    		int rgb, alpha;
    
    		width = pixieimg.getWidth();
    		height = pixieimg.getHeight();
    		for (y = 0; y < height; y++)  {
    			temp = 0;
    			for (x = 0; x < width; x++) {
    				rgb = pixieimg.getRGB(x, y);
    		 		alpha = (rgb>>24)&0xFF;
    		 		/* 下面的if-else语句的含义就是下面注释版的if语句的优化版,即:
    		 		 * 将“不透明”的像素拼接成一个“区域”。
    		 		 * 所有“不透明”的像素就是在抠图时没有被抠掉的像素。
    		 		 * 如果是使用下面注释版本的话,要一个像素一个像素添加,那么大一双皮鞋,要两分钟!!
    		 		 * if (alpha != 0) {
    		 		 *		Rectangle temppixe = new Rectangle(x, y, 1, 1);
    				 *		pixie.add(new Area(temppixe));
    		 		 * }
    		 		 */
    		 		if(alpha != 0) {
    					if (temp == 0)
    						temp = x;
    				} else {
    					if (temp != 0) {
    						Rectangle temppixe = new Rectangle(temp, y, x - temp, 1);
    						pixie.add(new Area(temppixe));
    						temp = 0;
    					}
    				}
    			}
    		}
    		return pixie;
    	}
    
    	public static void main(String args[]) {
    		// 22.png就是哪个小皮鞋
    		String pixieicon = "22.png";
    		// 11.png是那双大皮鞋
    		File file = new File("11.png");
    		BufferedImage pixieImage = null;
    		ImageIcon button_icon = null;
    		try {
    			pixieImage = ImageIO.read(file);
    			button_icon = new ImageIcon(SkinShoeDemo.class.getResource(pixieicon));
    		} catch (Exception e) {
    		}
    		SkinShoeDemo demo = new SkinShoeDemo(pixieImage, button_icon, pixieicon);
    		demo.setVisible(true);
    		// 切割吧!
    		com.sun.awt.AWTUtilities.setWindowShape(demo, demo.getSkinshoeShape(pixieImage));
    	}
    }
    

    看看效果呗:
    在这里插入图片描述
    只要不是大皮鞋区域,鼠标点击都是透明的:
    在这里插入图片描述

    这是真正意义的 不规则窗口


    关于抠图

    我现在简单说一下这个效果的前置要求,必须对两双皮鞋的图片进行 抠图 预处理。

    先来看一下定义窗口外观的大皮鞋原图:
    在这里插入图片描述
    显然,按照常规,这是一张 四四方方 的图,矩形的。也就是说,这张图包含了 皮鞋前景白色背景 两个部分。如果拿这个图做我们的不规则窗口的11.png,将会是失败的,因为那个白色的背景并不会由于其Alpha值(含义马上会讲,这里只是代码的观感)等于0而被排除在有效范围之外:

    rgb = pixieimg.getRGB(x, y);
    alpha = (rgb>>24)&0xFF;
    

    Alpha的值等于0而被放逐在我们需要的有效区域以外,但是原图的矩形区域内包括背景在内的所有像素的Alpha值均不为0,为什么?

    我们单看白色的背景,换句话讲,白色背景的特性如下:

    • 颜色:有颜色,白色
    • 透明度:不透明(是的,它并不透明!)

    一张图片的每一个像素,均会包含上述两个性质,一个颜色,一个透明度。这两个性质被保存在一个4字节的数字里,其中的颜色占据3个字节,分别保存三原色的各自分量,余下的1个字节保存透明度信息,很巧妙。

    最常用的定义,4个字节定义如下:

    typedef struct RGB_info {
    u8 rgbBlue; 	// 蓝色分量
    u8 rgbGreen; 	// 绿色分量
    u8 rgbRed; 		// 红色分量
    u8 rgbAlpha; 	// 透明度
    } RGB。
    

    这个叫做 带Alpha通道的RGB24 标准。

    很少有图片在生成的时候就会设置某些像素的Alpha为完全透明,所以这个需要我们自己来 ,把背景抠掉即可,所谓的抠掉,就是将背景像素的Alpha值设置为0。

    一般抠图程序很容易写,但是比较麻烦,原理很简单, 只要能通过RGB颜色信息识别出前景和背景,那么把背景像素的Alpha设置为0即可。

    问题是如何识别。在我们这个例子中,很简单,把白颜色的给设置透明即可,但是有些像素并不是纯白,而是 接近白,灰白… 这让程序去定义一个范围吗?似乎这个范围如何来界定又是一个问题,最终就陷入了AI,哦,很高大上的领域!

    还是用肉眼识别吧,一切抠图者自己来决定。这就要使用抠图工具了。这种工具一般让你自己用圈点指针自己标示那些部分要设置为透明,比如套索,画笔之类的。

    昨晚让老婆用美图秀秀给帮忙把皮鞋前景给抠出来,但是没有成功,后来我找了一个在线的工具:
    https://ue.818ps.com/clip/
    在这里插入图片描述
    还算挺方便的。反正也只是用一次,足够了。

    最终把那双要做按钮的小皮鞋也完成了抠图:
    在这里插入图片描述
    用这两张图就可以制作不规则窗口和不规则按钮了。

    最后让我们的SkinShoeDemo换一张图,看看效果:
    在这里插入图片描述
    给包括小小在内的演示了这个之后,都说好。


    X11的畅想

    本来我是想用JNI调用X11实现的动态库来实现这个 大皮鞋?窗口 的,但是失败了。我一直以为这是很容易成功的。

    当初既然我可以用三个点来定义一个三角形,我就自然而然想到可以用 皮鞋轮廓的N个像素点 来定义一个N边形来 模拟大皮鞋?围绕着的区域 ,N是多少呢?就看大皮鞋图案的外轮廓有多少个点了。这个想法很合理。

    首先我要先得到大皮鞋的轮廓。

    我用下面的代码获得,命名为Outline.java:

    import java.awt.image.*;
    import java.io.*;
    import javax.imageio.ImageIO;
    
    public class Outline {
    	static File src = null; 
    	static File dst = null;
    	static BufferedImage img = null;
    	static BufferedImage outline = null;
    
    	public static void main(String[] args) throws IOException {
    		int i, j, width, height;
    		int rgb, rgb1, rgb2, a1, a2, a3;
    		src = new File(args[0]);
    		dst = new File("outline_" + args[0]);
    		img = ImageIO.read(src);
    		width = img.getWidth();
    		height = img.getHeight();
    
    		outline = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    		// 纵向扫描
    		for (i = 1; i < width - 1; i++) {
    			for (j = 1; j < height-1; j++) {
    				// 捕捉变化
    				rgb = img.getRGB(i, j);
    				rgb1 = img.getRGB(i + 1, j);
    				rgb2 = img.getRGB(i - 1, j);
    				a1 = (rgb>>24)&0xFF;
    				a2 = (rgb1>>24)&0xFF;
    				a3 = (rgb2>>24)&0xFF;
    				if(a1 != 0 && (a2 == 0 || a3 == 0)) {
    					// 为了轮廓线清晰,特使用白色来描绘“边界像素周边的四个点”
    					rgb |= 0xffffffff;
    					outline.setRGB(i, j, rgb);
    					outline.setRGB(i, j - 1, rgb);
    					outline.setRGB(i, j + 1, rgb);
    					outline.setRGB(i + 1, j, rgb);
    					outline.setRGB(i - 1, j, rgb);
    				}
    			}
    		}
    
    		// 横向扫描
    		for (i = 1; i < height - 1; i++) {
    			for( j = 1; j < width-1; j++) {
    				// 捕捉变化
    				rgb = img.getRGB(i, j);
    				rgb1 = img.getRGB(i, j + 1);
    				rgb2 = img.getRGB(i, j - 1);
    				a1 = (rgb>>24)&0xFF;
    				a2 = (rgb1>>24)&0xFF;
    				a3 = (rgb2>>24)&0xFF;
    				if (a1 != 0 && (a2 == 0|| a3 == 0)) {
    					// 为了轮廓线清晰,特使用白色来描绘“边界像素周边的四个点”
    					rgb |= 0xffffffff;
    					outline.setRGB(i, j, rgb);
    					outline.setRGB(i, j + 1, rgb);
    					outline.setRGB(i, j - 1, rgb);
    					outline.setRGB(i + 1, j, rgb);
    					outline.setRGB(i - 1, j, rgb);
    				}
    			}
    		}
    
    		ImageIO.write(outline, "png", dst);
    	}
    }
    

    以上这个程序,当我用大皮鞋图片的名称 11.png 作为参数执行时,会输出一张轮廓图片 outline_11.png ,输出图片效果如下图所示:
    在这里插入图片描述
    嗯,是一双皮鞋?!!

    我用这个轮廓干什么呢?我要得到一个数组啊。于是我在上述代码的 outline.setRGB 处打印一个序列:

    int idx = 0;
    ...
    System.out.println("outl[" + idx + "].x=" + i + "; out[" + idx + "].y=" + j + ";");
    idx ++;
    

    打印的结果就是:

    root@name-VirtualBox:~# java Outline 11.png |more
    outl[0].x=29; out[0].y=722;
    outl[1].x=29; out[1].y=723;
    outl[2].x=29; out[2].y=724;
    outl[3].x=29; out[3].y=725;
    outl[4].x=29; out[4].y=726;
    outl[5].x=29; out[5].y=728;
    outl[6].x=29; out[6].y=729;
    outl[7].x=29; out[7].y=730;
    outl[8].x=29; out[8].y=731;
    outl[9].x=29; out[9].y=732;
    ...
    outl[1567].x=772; out[1567].y=293;
    

    我将这个打印结果重定向到一个文件中,然后将其include到JNI的本地代码。

    我的意图是希望这些 XPoint 可以生成一个 1568边形! 我希望它们可以定一个Region,然后让X11 shape去框定窗口的裁剪范围:

    outl[9].x=29; out[9].y=732;
    ...
    outl[1567].x=772; out[1567].y=293;
    	
    region = XPolygonRegion(outl, 1568, EvenOddRule);
    XShapeCombineRegion(dpy, window, ShapeBounding, 0, 0, region, ShapeSet);
    

    初看这些操作,和 Java com.sun.awt.AWTUtilities.setWindowShape 的操作几乎是一样的,定义一个Region而已,我用1568边形来框定这个窗口的范围,可行啊!

    然而事与愿违!

    问题出在了 如何画N边形 这件事上。我们希望系统会 逐个地将我们的皮鞋外轮廓点连接起来,形成一个多边形 ,但系统如何解释 逐个地 ,这是问题。

    请注意 XPolygonRegion 函数,它的最后一个参数确定了 如何判断一个点是否在该Region的内部。 它的取值只有两个:

    The fill-rule defines what pixels are inside (drawn) for paths given in XFillPolygon() requests and can be set to EvenOddRule or WindingRule. For EvenOddRule , a point is inside if an infinite ray with the point as origin crosses the path an odd number of times. For WindingRule , a point is inside if an infinite ray with the point as origin crosses an unequal number of clockwise and counterclockwise directed path segments. A clockwise directed path segment is one that crosses the ray from left to right as observed from the point. A counterclockwise segment is one that crosses the ray from right to left as observed from the point. The case where a directed line segment is coincident with the ray is uninteresting because you can simply choose a different ray that is not coincident with a segment.

    For both EvenOddRule and WindingRule, a point is infinitely small, and the path is an infinitely thin line. A pixel is inside if the center point of the pixel is inside and the center point is not on the boundary. If the center point is on the boundary, the pixel is inside if and only if the polygon interior is immediately to its right (x increasing direction). Pixels with centers on a horizontal edge are a special case and are inside if and only if the polygon interior is immediately below (y increasing direction).

    此乃问题之所在了。fill-rule 的局限导致了皮鞋内部的点不一定被判定为 内部

    虽然没能成功使用外轮廓数组构造一个Region调用XShapeCombineRegion完成不规则窗口的切割,但是我知道已经提供 com.sun.awt.AWTUtilities.* 的肯定是有办法做到的:

    • 要么自己调用JNI,加以适配
    • 要么直接返回UNSPPORTED

    没空研究X11细节,GUI本来也就不是我的关注点。但偶尔,我依然会花点时间探究一下若干年前遗落的问题,这是改变不了的事实。


    JNI直接操作AWT本地同位体

    洋洋洒洒写到这里,相信已经把Java如何调用JNI或者自身的API实现不规则窗体说的很清楚了,但是还有点小遗憾。

    我们看上文中引述的本地代码 cutWindow.c ,其中操作的window句柄是通过字符串Title查找而来的:

    window = findWindowByName(dpy, DefaultRootWindow(dpy), name);
    XShapeCombineRegion(dpy, window, ShapeBounding, 0, 0, region, ShapeSet);
    

    如果启动了同样Title的两个实例,会怎样?这就不得不将这多个同样Title的window通过别的键值进行区分。

    正确且直接的做法应该是Java直接将window句柄通过参数传递进来!这样就可以直接操作明确的window控件了!

    问题是Java代码中如何获得本地同位体的句柄呢?理论上来讲,这个系统底层的概念在Java API的层面应该是不可见的,Java代码只认识 跨平台的Frame/JFrame 这种,不可能会认识 Windows的HWND,X11的Window 的!

    然而,如果你不追求通用性,不追求跨平台(窗口不规则切割这件事本来就是平台相关的),办法嘛,必然是有的。我下面直接给出代码吧。

    1. 先看 PeerDemo.java:
    import java.awt.*;
    import java.awt.peer.*;
    import sun.awt.X11.*;
    
    public class PeerDemo extends Frame {
    
    	private native void cutWindow(long display, long hwnd);
    	static {
    		System.loadLibrary("cutWindow");
    	}
    	WindowPeer peer = null;
    	XBaseWindow base = null;
    	long hwnd = 0;
    
    	public PeerDemo() {
    		setSize(500,500);
    		setUndecorated(true);
    		setVisible(true);
    		this.peer = (WindowPeer)this.getPeer();
    		this.base =(XBaseWindow)peer;
    		this.hwnd = base.getWindow();
    	}
    
    	public static void main(String args[]) {
    		PeerDemo demo = new PeerDemo();
    
    		demo.cutWindow(XToolkit.getDisplay(), demo.hwnd);
    	}
    }
    
    1. 再看本地方法声明 PeerDemo.h:
    JNIEXPORT void JNICALL Java_PeerDemo_cutWindow
      (JNIEnv *, jobject, jlong, jlong);
    
    1. 最后看本地动态库代码 cutWindow.c:
    #include <X11/extensions/shape.h>
    # include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <jni.h>
    
    JNIEXPORT void JNICALL Java_PeerDemo_cutWindow (JNIEnv *jenv, jobject o1, jlong display, jlong hwnd)
    {
    	Window window;
    	Display *disp;
    	Region region;
    	XPoint p[3];
    
    	disp = (Display *)display;
    	window = (Window)hwnd;
    
    	p[0].x = 250; p[0].y = 100;
    	p[1].x = 450; p[1].y = 425;
    	p[2].x = 50; p[2].y = 425;
    
    	region = XPolygonRegion(p, 3, EvenOddRule);
    	XShapeCombineRegion(disp, window, ShapeBounding, 0, 0, region, ShapeSet);
    }
    

    非常简单的一气呵成,看看效果:
    在这里插入图片描述
    编译时的Warning是必然的,Java的Doc上已经说的很明白了:
    在这里插入图片描述
    getPeer意味着关联了本地,承诺跨平台的Java怎么可能暴露出这么低层次的接口呢。

    结束了吗?嗯,差不多了。但是且慢!

    还记得上文中我的失败吗?我想勾勒出皮鞋?的轮廓,然后把这些轮廓的像素点(超级多的点,至少好几千个吧)传递给本地代码,企图在本地代码中用这些轮廓点构建出一个X11的Region结构体:

    region = XPolygonRegion(outline_points, 3188/*举个例子,或许更多吧*/, EvenOddRule);
    

    然后呢,将其传递给X11的 XShapeCombineRegion 函数进行切割。然而遗憾的是,X11并不是如我希望的那般将这些点按照皮鞋的样子顺序连接起来成为一个皮鞋外形的,它有自己的连接方式。很遗憾,失败了(也许是我对X11不太了解,我暂时只能理解到这个程度)。

    然而,X11提供了另一种 构建任意形状 的方法,即 组合矩形

    这很好理解,既然所有的图像在计算机中都是一个个的像素组成的,而每一个像素就是一个长宽均为1的矩形,那么 任意形状至少可以用这么多像素矩形组合而成 。作为优化,还可以将矩形的数量减少到最少,这是一个算法问题,我这里仅仅给出一个思想。比如,依然是那个皮鞋的轮廓,矩形可以如下分割:
    在这里插入图片描述
    细微之处我没有画,反正就是这个意思。

    X11提供了组合不同大小矩形的API,即:

    void XShapeCombineRectangles (
    	Display *dpy,
    	XID dest,
    	int destKind,
    	int xOff,
    	int yOff,
    	XRectangle *rects,
    	int n_rects,
    	int op,
    	int ordering);
    

    参数很丰富,我还真没搞明白,详情可以参见X11 Shape Extension的文档:
    http://www.xfree86.org/current/shape.pdf

    不过给出个例子还是可以的。Java代码如下:

    import java.awt.*;
    import java.awt.peer.*;
    import sun.awt.X11.*;
    import javax.imageio.ImageIO;
    import java.net.URL;
    import java.io.*;
    import java.awt.geom.*;
    import java.awt.image.*;
    
    public class PeerDemo extends Frame {
    
    	private native void cutWindow(long display, long window);
    	static {
    		System.loadLibrary("cutWindow");
    	}
    	WindowPeer peer = null;
    	XBaseWindow base = null;
    	long hwnd = 0;
    
    	public PeerDemo() {
    		setSize(500,500);
    		setLocation(200,300);
    		setUndecorated(true);
    		setVisible(true);
    		this.peer = (WindowPeer)this.getPeer();
    		this.base =(XBaseWindow)peer;
    		this.hwnd = base.getWindow();
    	}
    
    	public static void main(String args[]) {
    		PeerDemo demo = new PeerDemo();
    		demo.cutWindow(XToolkit.getDisplay(), demo.hwnd);
    	}
    }
    

    本地代码如下:

    #include <X11/extensions/shape.h>
    # include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <jni.h>
    
    JNIEXPORT void JNICALL Java_PeerDemo_cutWindow (JNIEnv *jenv, jobject obj, 
    										jlong display, jlong hwnd)
    {
    	Window window;
    	Display *disp; 
    	XRectangle rects[4];
    	XRectangle *pRect = &rects[0];
    
    	disp = (Display *)display;
    	window = (Window)hwnd;
    
    	// 我们组合下面4个矩形:
    	rects[0].x = 0;
    	rects[0].y = 0;
    	rects[0].width = 100;
    	rects[0].height = 100;
    	rects[1].x = 100;
    	rects[1].y = 0;
    	rects[1].width = 100;
    	rects[1].height = 50;
    	rects[2].x = 200;
    	rects[2].y = 0;
    	rects[2].width = 10;
    	rects[2].height = 400;
    	rects[3].x = 0;
    	rects[3].y = 100;
    	rects[3].width = 10;
    	rects[3].height = 300;
    
    	XShapeCombineRectangles(disp, window, 
    							ShapeBounding, 0, 0, pRect, 4, 
    							ShapeSet, YXSorted);
    
    }
    

    效果如下图所示:
    在这里插入图片描述
    有点这个意思了。如果把这些矩形按照这个思路不断细化,就可以出现皮鞋外观了。


    什么是编程

    还记得 《Java Swing 2nd Edition》 这本书吗?

    我当时买了中文版之后,太厚,切割成了3部分,然而最终还是没有读完,惭愧。现在它的代码资源放到github了:
    https://resources.oreilly.com/examples/9780596004088
    我记得第28章的那个圆形飞梭控件非常好,嗯,Java Swing自己定义的不规则控件,是的,它是Swing自己画出来的。当时非常震撼。

    现在回头想想,有啥好震撼的呢,计算机屏幕上的所有像素不都是画出来的吗?关键是 如何画 才是根本,而这又涉及到了算法。

    如果不知道JNI,很难用Java做出不规则控件,如果知道了JNI,至少知道了有个渠道可以做,然而此时你还必须懂Win32 API/X11 API这些,你才能真的动手去做。之后如果这些全都懂了呢?就以为自己可以任意画界面了吗?

    不不不,这才到了关键的地方,这才是刚刚开始,比如上文中所说的,如何把皮鞋切割成数量最少的矩形,这比如何调用X11 API重要得多了,这里面奥妙太深了。

    换句话说,你想画画,目前你只是买了本子,画笔,画板,并且知道了如何使用它们,这些都是 必先利其器 的事,并不是画画本身!

    所以说呢,不是精通几个API,精通几门编程语言语法,精通几个工具的使用,就是精通编程了。甚至即便你精通很多系统底层的调试方法,你也不一定懂编程。你只是精通工具如何使用而已。

    比如我,我精通如何摆置系统底层,如何摆置协议栈,但是这并不意味着我精通编程,编程的核心是算法,而不是如何摆置代码本身。

    编程是一种如何组织逻辑的艺术,它不是一种如何使用编程语言的技术 编程语言只有一种用法,就是 用对它

    换句话说,如果你精于如何组织逻辑,那么即便是使用自然语言,你也可以精通编程(这通常见于物理科学家,律师,外交官等职业)。编程语言只是实现这种逻辑组织的手段而已(所以生物学家,文学家很多也精于几种编程语言,大多数用于数据分析)。所以,一定要把 会编程语言会编程 区别开来。

    以上形而上的说法如何形而下落地?这就要将行业的分工细化为 算法工程 两个方向。

    算法侧重业务逻辑本身,而工程则是为了更好的组织算法,使得其符合工业约束,成为优质的产品。比如说可扩展性这个就是工程要做的事,而效率则大部分是算法的工作。

    最后,我觉得我还是不会编程,在历经的学习和工作过程中,我掌握了系统的工作原理,底层的调试技巧,但是我依然吃力于编程,这意味着我的逻辑组织混乱,但是这并不是什么缺点更不是缺陷,这意味着我可以天马行空,而这正是定位棘手问题所需要的。所以说,摆正自己的位置最重要,不会编程没什么丢人的。


    勘误:全文均没有出现 “一双皮鞋” ,仅仅是 “一只皮鞋” 而已!更正。

    浙江温州皮鞋湿,下雨进水不会胖。

    展开全文
  • 可毕业后回首,却很少有能说,自己从来没有迷茫过。迷茫,仿佛就是一团乌云,笼罩在每一个心中怀有抱负的的头上。每当夜深人静,思绪归于对自己人生未来的严肃思考,不知去往何处的苦闷,再加之不断迫近的升学/...

    引言

    我对于本科时光的印象,还停留在那所普通 211 大学的建筑物之间,我坐在大学的时光长廊里,满眼望去,都是经历的过的故事。可毕业后回首,却很少有人能说,自己从来没有迷茫过。迷茫,仿佛就是一团乌云,笼罩在每一个心中怀有抱负的人的头上。每当夜深人静,思绪归于对自己人生未来的严肃思考,不知去往何处的苦闷,再加之不断迫近的升学/就业选择的压力,尤其是一些看似周密的计划,由于想把每一环都做的尽善尽美,往往不仅减少了反馈(一切的目标、报偿都在最后)、还因为人生的不确定性而很容易失败:以保研为例,我常常见到一些平常学习认真、热心参加学术活动,但是不关心所在院系制度的人,到保研时因为一些硬性规定(如必须完成某些并不喜欢的所谓保研必修课)、或者是不公平的排名标准(比如说活动成绩、竞赛成绩计算很高,导致成绩上产生的差距在计算时几乎没什么权重)导致原本计划了几年的保研机会失之交臂,而此时离考研也已不远,若无提前准备,也往往容易落榜。在这样的过程中,亲历者绝望、愤懑甚至因而抑郁的,我都见过,以至于都有些麻木了:太阳照常升起,一个人的悲哀苦痛,回到这个宏大的时代与社会中,连一粒尘埃也算不上;而那些看多了这样的故事的人,也难免兔死狐悲,故而更难聚集其一股欲与天公试比高的拼搏的意志。

    2019年7月29日,《中国青年报》刊发《大学生抑郁症发病率逐年攀升 大一和大三高发》引发读者广泛关注。有31.2万网民参与了中国青年报微博发起的 大学生抑郁症发病率逐年攀升,你觉得自己有抑郁倾向吗的网络投票,其中认为自己有抑郁倾向且情况很严重的达到了8.6万,占比27.6%,若是统计为有过低沉的倾向,则有约18万人,占比为60.8%。

    一些市面上的流行语录,似乎也从侧面说出了这种感觉:什么我所得到的不过是侥幸,纵然得到了一时的世俗意义上的成功,由于从来没有对自己的人生命运有一个通盘的规划与目标,即使通过搜集到的一些信息、经验走了一些捷径,但是短暂的兴奋后,却又会重新回到迷茫与空虚中来。我忍不住还是要发问:上了好学校、找了好工作、赚了不少钱,那然后呢?倘若有一步,没能像这样环环相扣地被达成,那又该怎么办呢?纯粹的人往往能在一个方向做出不俗的成绩,可过于纯粹,就难以承受突如其来的打击,难以接受自己的规划被命运玩弄,付之东流。

    回想我的大学生活,也的确是这样:一起朝夕相处的同学朋友们,虽然可以一起感慨未来的未知与自身的无力,可自己的命运最终还是只能自己把握,总要面对那条只能一个人走完的路。而在我在大学期间认识的大约几百人里,真正能有坚定的三观信仰,又努力去做的(即所谓知行合一的),实在是凤毛麟角,而且这往往出自他们不断地痛苦地思考与试错,有时甚至还需要一点运气。

    人本应该是越长大越坚强越成熟的,可在大学期间因迷茫和各种诱惑堕落的大多数人,其心志能力,往往连高中时代都不如,既失去了当初的纯粹与坚定,又没有真正获得一些面对问题、解决问题的勇气与能力。这种普遍的迷茫,不只是存在于那些混吃等死的人中,我认识的无数的名列前茅、努力拼搏的同学,也还是深受其苦。笔者也是前两年,才逐渐开始想明白。像这样大环境的精神空虚与迷茫,究竟是谁的责任呢?

    毕业晚会时,一曲谁的青春不迷茫唱出了我的心声,歌词非常写实,也写出了很多人的青春,可是让我有些近乎条件反射般的讨厌:谁的青春又想迷茫呢?

    一个人、一小群人的迷茫,尚且可以认为是个人心理问题,抑或是环境,甚至是遗传;可成批的学生都怀疑人生、看不到未来的出路、不知道自己要干什么,这究竟是谁的责任呢?辗转反侧后我觉得需要用文字来阐述一下我的观点。

    那么究竟为什么会变成这样呢?就有没有什么合理的办法、科学的想法可以借鉴呢?作为个人,我们是不是也应该参考古今中外的真正的大人物、向那些慧人借鉴呢?

    我的青春并不想迷茫,我相信大家的青春也都不想迷茫。虽然因为运气我有了一点成绩,但是我觉得这不少都得归于时运的赐予,不把这样的经验分享给更多还在痛苦思考中继续前行的人,我无法获得良心的安宁。

    本文将从成因开始着手分析迷茫这个问题,从问题的产生到表现、再到教育制度、人性的缺点、再到我们可以锻炼的能力以及可以采取的想法(由于笔者也算是半个做技术的,相关的能力将主要以技术为基础)。

    迷茫问题的定义与分析

    在报刊或者一些网络评论中,偶尔也会看到老一代的人批判现在的年轻人事多,是的,当代的大学生,与过去的时代,是有一些不同的。

    1993年,全国取消了粮票制度,这也意味着,这一代人基本是没有经历过饥饿与那种迫切的生存的问题。

    相反的,更多的人考虑的是我活着有什么意义,表现在流行文化上,就是讲求个性,讲究表现自我,想寻找不同寻常的意义,而不只是活着。因此带来了更加自由的发展,以及求而不得的各种迷茫。

    不过,为什么又一定是大学生呢?中学生的阶段、我们并不是没有其他想法,但是的确就没有那种难忍的迷茫。

    因为对于大多数普通学生而言,大学以前的内驱力是很明显的。

    由于中国绝大多数中学都在以高考成绩作为其神圣而不可动摇的目标,一系列神奇的口号也能体现这一点,譬如某些中学曾经打出的没有高考,你拼得过官/富二代吗?提高一分,干掉千人!不苦不累,高三无味;不拼不搏,等于白活!等等。

    从现实的功利,到亢奋的鸡血,到想压人一头的野心,这些口号就是这种高考文化的最好体现。

    从报刊书籍到街谈巷议,从学校老师到家长学生,能不受这种文化影响的,很少很少,或多或少都要受此裹挟。

    所以一切的其他梦想并没有被真的解决了,而是以一句你高考考好了,未来都能实现的,其实是某些落榜生的绝望,也是受到了这句话的影响:那我要考不好,我的人生是不是就废了?

    将一次考试完全的神化,对于人的长期热情,实际上起到了杀鸡取卵的作用。

    因为这种热情,随着高考的结束,在大多数人身上重新消失了(既然高考都是所谓的最后一战了,之后岂不是就应该安享人生了?)。

    而且往往因为此前压力太大,还会引起加倍的反弹,究其原因,还是因为大学没有了那种统一的价值标杆,正如一句近年来很火的评论高中忙的理所当然,大学忙的莫名其妙(说一句题外话,这句话原本是我一个大学同学随手写的说说,写完当晚转发破万)。

    即使是清华北大,年年都有人因为沉迷游戏退学的,至于我自己的所见所闻,沉迷游戏的人,甚至可能不止百分之二十,每个年级因严重沉迷而退学的,也屡见不鲜。

    严重者如此,症状较浅者因为没有目标而沉迷游戏,透支自我,意志消沉的,那就不计其数了。人生尚有许多美好故事可以经历,而他们却早早地选择了这样的透支

    不管怎么样,随着高考的结束,这种受全社会标榜的奋斗价值仿佛就告一段落了一样。一群被社会舆论、集体主义裹挟着完成了高考的人,却一下子被投入了一个多元化价值的环境里,什么都好像是有意义的,什么又都好像是没有意义的,那种确定性的价值的丧失,让人产生了巨大的恐惧与不适应。

    这就是迷茫的定义了:由于价值多元化,不能找到并坚守属于自己信仰的价值并坚定决心的去追求

    这种迷茫的弥漫与试图消解,也构成了当代文化的一个大类,或者与之交织起来,形成了更深层的恶性循环。

    读书

    被认为最好的方法一般来说是多读书。可即使是读书,如果读不到一定深度,往往也并没有什么特别的价值;即使是似乎对对口解决这个问题的哲学,其最新的发展,也就是现代西方哲学,依旧有一个重要的问题,那就是虚无主义

    西方的主流精神史说来也好笑,过去的几千年一直迷信上帝(或者神及其等价物),一切价值都可以从那里推出来;

    然后到文艺复兴与启蒙运动,短暂地迷信了一会人类理性的作用;

    结果因为理性的滥用,尤其是试图用理性来论证人生的意义,就走到了问题的反面——人生的意义不是浅薄的理性可以论证的,所以尼采说上帝死了(狂热的信仰神的意义是不能用逻辑论证的)。

    这就是现代西方哲学让人陷入的所谓精神荒漠,凡是想要真诚研究探讨这些问题的,就越是觉得人生没有意义。

    至于其他种类的书籍,学心理学本指望能搞清楚自己为什么抑郁,结果一堆又大又空洞的人格模型性格模型之类的名词扔来,解释什么内容都好像有点道理,但是想更直接的使用分析具体问题,发现总归又差了点,只看书肯定是分析不了的;

    学社会学本指望能搞清楚社会如何运行,结果大杂烩似的讲一堆似是而非的社会建构理论,然后分析各种人群的特性,感觉明白了好多东西,但是这跟我应该做什么又有什么关系呢?

    至于经济学、政治学,都是讲了一堆有时都不一定能自圆其说的道理,且不提理解上往往难度较高,即使真的理解了,也很少存在什么让人能一定要坚持的道理。

    虽然口头上和心里觉得很多理论是不错,但是为了这些抽象的信念而献身,似乎又并没有那么强的内驱力,而且执行起来也不知从何着手。

    是的,市面上大多数的关于读书的宣传,往往也就只能把书读到这个程度了,读书当然不是坏事,浅阅读才是,所谓浅阅读,就是不能将书籍与自己的思考、经验、对社会实际的认知结合,所以有一句流行语就反映了对这样的理论的嘲讽:有什么卵用呢?是啊,什么东西只知道这么肤浅的内容,看着样样都知道,其实呢:学了金融学也不懂金融体系的运行,学了投资学炒股还是一样亏本,看了社会学经济学,问他为什么现在房价这么高、中国国民经济的体系结构究竟是怎么样的,未来将会发展的产业又是什么……不用问,只是读到上面那种程度,是根本不可能答得出这些问题的。

    可是,读书并不是目的本身,很多名著也不是为了写作而写作的,《资本论》是为了分析清楚在资本主义条件下,社会的各种成员从商品到企业再到产业的价值分配问题,最终揭示整个经济体系运作的机理,从而教育劳动者为了自己的合理利益而斗争。

    而很多营销号,就往往只会售卖这些廉价的杂学知识、小技巧、人生社会的一些或者正确而无用的废话,很少能真的讲出一些具有可操作性的深度思,而这是古往今来一切有价值的好书的共性:好书不仅仅是议论本身,它们本质上都是作者在自己认识世界、改造世界的过程中积累而成的经验,由于作者的时空所限、因为文字本身表达的模糊性所限,自然而然会出现老子所谓道可道,非常道(真理如果能被文字表达出来,那么就不会是永久的真理)的现象。而判断什么对、什么不对,都需要读书者自己努力思考、在社会中进行实践。知易行难,这就是肤浅的、不去把一些似是而非的东西真正考证清楚的书籍、学问往往真的没什么卵用的本质。

    俗世标准的成功门槛太单一

    回想我的中学时代(这种县中的应试教育模式,应该也能让很多人同样想起自己的中学时代吧)

    每天我们会被要求早上六点五十之前到校,然后开始早读,并开始一天的灌输性的课程,然后完成每门课要求的各种作业、试卷。

    其中主要的创造性、思考性的工作,可能也就在跟老师一起思考问题以及做作业中了,至于课外的内容,即使不是完全不涉及,能花的时间也是很少的。

    由此带来的结果,就是虽然获得了不错的高考成绩,考上了不错的大学,但是上了大学后却发现学不进去了很不适应新的上课方法,因为没有那么多针对很细节的知识点都做出来的广大的题库了(高中时,即使是很小的知识点,肯定当晚的作业习题就会做个好几题),而自己把一个个知识点弄得条理分明的能力,并没有得到过有针对性的锻炼。

    大量的学生,即使认真学习,也不知从何下手,往往到大二大三,可能才渐渐适应大学的课程松散而作业不多的情况。 但是,很多人上了大学之后,也还是摆脱不了这种鸡血的生活,强迫症似的逼自己变得优秀,一心追求更高的分数、更多的竞赛等等与高中时代别无二致的评价体系中的成功

    再演变下去,那就是更好的研究生名额、工作,更高的薪水…

    那再然后呢?为什么一定要这样?比别人好就行了吗

    于是在学会反思之后,很多人也不能摆脱这样的迷茫:这样做自然不会让自己变的很坏,可是离那种指点江山、意气风发的少年英雄的形象,似乎也实在是看不到什么接点,活着难道就是为了时时刻刻在这种标准中比别人好那么一点吗?

    而且最重要的是,不像谁都会关心你的高考一样,上了大学之后,除了父母,几乎真的没什么人会很关心的你的成绩如何了,于是很多人渐渐选择了退出这种竞争。

    当然,除此以外也可以追求一些别的成功:去做各种各样的活动、志愿者等等,除了少数真的明白自己在做什么的人,大多数人也还是多了些经历、少了些激情,因为没有明确的目标指引,没有明确的意义的驱动,这些平庸的优秀实在不能让人满意。

    表现在工作上,也就是近来被人批判的所谓奋斗逼,不是奋斗不对,是为了奋斗而奋斗,实在是很可悲的。

    可是,人之所以高贵于动物,在于人会反思、会追问意义,如果一个人被突然要求像西西弗斯一样,每天把一个大石头推上山、一旦到了山上就推下去,于是周而复始,而没有一个明确的目标与意义,无论是多么坚定的人,都难免发问:像这样活着,有什么意义

    现代很多男性,为物欲与社会的虚名浮利所迷,觉得只需要迎合所谓丈母娘的爱好,有一个好工作(或者年薪够高)、有车有房,人生好像就圆满了,于是人的价值几乎就只剩下了钱,若是碰巧得到,方还好,可欲壑难填,赚了这么多,总是会一山望着一山高,永远得不到真正的意义。而且,不客气的说一句,像这样的成功男士,除非运气极佳,大多难守那么多的财富,也很难获得真正的精神上的完满。当他有一天开始反问自己:像这样活着,我为了什么?此时就是所谓中年精神危机的开始了。

    追求世俗的成功并没有错,但是单纯追求别人口中的成功,不过是把自己信仰的主宰权交给别人,而一个有独立意志的人(在古书中往往就是所谓君子、大丈夫之类)是绝不应该满足于此的。就像作为一个刻板印象出现的程序员群体,就是这种化身:钱多话少死的早,除了像机器一样被劳动异化为非人(实际上没有独立意志的人),什么东西都交给别人、社会去评判、去决定,自己心中没有对于真爱、真理、正义的绝不放下的那种热情与信念。像这样的人,哪怕年纪很大,也不过是一个大男孩罢了,甚至用这些年更火的词来说,就是巨婴

    古时的君子、英雄,为了改变他们眼中不合理、不完美的世界,投入各种变革、忍受千难万险、不断提高工作能力,他们清醒地认识到自己的能力的界限,只是耐心地、智慧地、一点一滴地往那个目标前进,如果有必要,他们还会舍生取义,这是因为在他们的生命中,有比他们的生命乃至一切都更重要的东西。而大男孩们,平常嘻嘻哈哈,遇到风浪,却不能挺得住各种打击,为自己理应守护的人或者理念战斗到底,这与所谓仗义每从屠狗辈,读书多是负心人颇有些不谋而合。这样的人只要能获得一些钱财,就可以赞美为成功,甚至飘飘然自以为大丈夫,不亦悲乎?

    享受

    那,既不想每天过的那么劳劳碌碌,也不去读书,如何呢?

    自然更是不行。

    为什么?

    现代社交媒体、信息平台太多了,一个年轻人至少可以从微博、微信公众号文章、今日头条类的新闻推送工具、知乎等APP(我认为99%的人至少用过上述一种或几种)上获取信息,这些信息还是会潜移默化的教育人,让人自然而然形成对人生意义,或者再不济,什么是成功的思考。

    由于执笔者自身往往局限性就很大,往往不过是一无所成的白面书生,所以写出来的文字往往也根本没有清晰的思想,只是迎合各种欲望和热点,或者空洞地谈论一些自己根本不能践行到底的思想。 所以阅读这些文字的人,潜移默化受其影响。

    故而得不到自己的意义,就觉得自己很失败,又不知有什么路可以走,若是心气不够高、能力又不足,就容易放弃治疗(放弃有条理的努力),变得很(觉得人生无意义又无可奈何,只能通过嘲笑自己与人生的荒谬而活下去)。

    每个看似荒谬的社会现象的背后,总有这种其实让人心酸的绝望,如果不是没办法、找不到出路,谁又想那么丧呢?

    此外,消费主义文化在资本的驱动下,时时刻刻在想办法侵蚀年轻人,抖音、快手之类的短视频,兜售口红、美食等等所谓精致生活。(校园贷之类的在较好的大学还不算太猖獗,但是借花呗严重提高不必要的消费还是家常便饭)

    其实就是把人需要的几种欲望包装一下:食欲(网红美食、奶茶)甚至性欲(各种小姐姐短视频的本质往往不过是软色情)。

    这些无所谓的东西,如果大量花时间沉迷其中,不仅消磨了人的时间,更是腐化了人的斗志,而且假借时尚与娱乐的名义,让一切对于它们的严肃批判都显得很反潮流

    虽然它或许是短期见效最快的缓解迷茫的办法,但是长远来看,这也是危害最大的方法,不过饮食宴乐,谁又能说一点不沾呢,适度的话,也有利于放松身心。

    更重要的是,它们降低了人们获取快感、反馈的阈值,让人很容易就想葛优躺,只想躺着获得直接的快感,从而渐渐陷入了一个难以振作的怪圈之中,导致所谓的行为成瘾,从精神到肉体都逐渐萎靡,身材走样还是小事,毕竟还能健身改变,养成了这样散漫乏力的精神习惯,志趣也便越来越卑下猥琐,要知道,人是一种很容易文过饰非的动物,一旦人开始不断地为自己的不作为寻找借口,比如说拖延症、比如说努力也是一种才能,我没有才能等等,我看很少有能真的治好的:反正我都有病了,你们就别指责我了,让我爱咋咋地吧!

    波伏娃曾经评论过:男人的极大幸运在于,他,不论在成年还是在小时候,必须踏上一条极为艰苦的道路,不过这是一条最可靠的道路;女人的不幸则在于被几乎不可抗拒的诱惑包围着;她不被要求奋发向上,只被鼓励滑下去到达极乐。当她发觉自己被海市蜃楼愚弄时,已经为时太晚,她的力量在失败的冒险中已被耗尽

    她是用这句话讽刺欧洲的女性被社会文化鼓励不去努力工作、开拓事业的,但是如果把主语的男人、女人,改换成不迷茫的人与迷茫的人,或许也并没有太大语病。

    小结

    以上三者,如果我们归结一下,有一个共同的本质:找不到人生的乐趣,因而产生不了对一些本值得热爱的东西的激情(即西方所谓passion)。

    信念与热情之所以重要,就在于其对于人的近乎绝对的强制作用,它就像康德口中的道德律令一样,一切恶习(尤其是懒惰与萎靡)在它面前都不能成为借口。有拖延症?没时间?没精力?脑子不够聪明?没钱没地位?都不能构成一个理由。倘若真的觉得一件事物是对的,比如说正义,自然就得为其负上各种各样的责任与义务,不论时间、不论空间,不论正在从事什么工作,一旦有了机会条件,就一定会把自己的才能、经验、资源统统用在这上面,这就是所谓激情,也就是驱动人去完成一些不得不做的事情的本源。

    人与人之间虽然可能的确有一些天赋、智商等等的差异,但是绝对没有想象中那么大,只是达到一个行业前 5%,都是完全可以通过努力解决的,所谓努力,不是说闷头搬砖,举一个极端的例子:当年轰动一时的暴走妈妈体重很胖,但是孩子手术需要移植她的器官,她就每天暴走二十几公里,恐怕她以前一个月都未必会运动这时一天这么多;对于很多需要智力的工作,如果真的到了非做不可的地步,查书、查资料、把能问的人、能用的资源统统用上,于是突破过去的眼界和能力,得到巨大的进步。而很多人呢,只是稍微遇到了一点挫折,就坐在地上,实在是没什么值得同情的:毕竟,什么英雄不是这样,一次一次超越自己的极限,才能获得最终的成功呢?

    所谓的领导气质(leadership),我觉得也就是基于这样磅礴的热情:百折不挠,一定要完成心中的伟大目标,并引领后来人一起走上这样的道路,关心他人的发展,关心团队的进步,这才是一个合格的领导。当他走的是一条能为了全人类谋福利的大路,并能走在人们的前面,高举旗帜、披荆斩棘,他就是人民的领袖,就是历史的巨人。这样的人的伟名也终将流芳百世,当人们重新呼唤起这些名字时,他们会明白,这就是伟岸的巨人,他们将永远俯视那些匍匐着的卑下的灵魂,而面对他们的骨灰,高尚的人们将洒下热泪

    对于教育制度的反思

    什么是创新型人才?甚至说,什么是创新?我不敢直接对其下一个定义,但是以我个人的经验来看,所谓创新型人才,与我们一直提倡的素质教育以及真正的高等教育,至少具有包含的关系,这又如何理解呢?

    现在的大学教育,自从大学扩招之后,一直是广受诟病的,一个概括性的形容词就是教育水平严重滑坡,简单来说,就是与扩招之前、与国际一流水平差距很大。

    在这一部分,我将以个人经历为主(本科在国内、有美国交换生经历,研究生也在美国),从三个方面,梳理一下我对国内工科教育体系不足之处的思考以及关于个人、体制可以做的一些补救的措施的理解。

    工科技术教学是否滑坡了?——与国外高校以及国内过去情况对比

    从当前国内高校的教育体系来看,很多课程出现了这样的问题:教学分离、教考分离。本科期间我修了大概六十门课程,自学的课程数,恐怕不低于半数,大量的老师上课只能照本宣科或者略微做一点阐发,且不提什么融会贯通、讲讲实际在工程、科研中的应用了,大多数情况下,也就只能保证讲的东西不出错,至于说有没有更好的办法、如何从初学者的角度提出便于思考理解的方法,一般来说,大多数课程都做不到这个层次。

    对于一门课程,我认为大致有三重境界:第一层是不出错,把需要讲述的课程以正确的形式展现其主干;第二层是一气呵成,老师能以自己的一套便于初学者理解的观点形成连贯、生动的讲解,在保证正确的前提下,使用多种多样的形式进行阐发,使得更多人能理解的更深刻清晰;第三层则是融会贯通,一个老师本身理应是这门课程相关领域的专家,那么自然应该有一些与其专家身份相称的高观点,更加深刻、灵活地阐述这些知识点在具体问题、尤其是一般人不能解决的问题上的合理应用,如何利用知识解决一些有实际意义的问题,这才是一门课理想的境地。

    但是正如这个分类,很多老师还停留在第一阶段,连像高中老师一样达到第二阶段的都往往称得上名师教学能手了,这在原本应该是有大师的大学,真是一件奇怪而讽刺的事情。

    与之完全不同的是,美国的工程教育则是世界有名的优秀。我举一个略极端的例子,我交换的美国一所州立旗舰大学,其学生数理基础平均水平,以国内高考衡量,应只有二本左右的水平(我曾不止一次在教他们题目时,遇到他们连高二左右的数学题都想不出来的情况,这个情况如果在我本科的学校,我可能已经直接骂了,而本校的新生,绝对会觉得不好意思而不是理所当然)。

    但是只从大三左右的专业课谈起,对比州立大学的EE(电气工程)专业与我本科院校的自动化专业(我校王牌专业之一)的学生,能熟练使用 matlab 仿真一个电路/控制系统,并在单片机等类似硬件设备上实现的比例,显然是州立大学的学生远高于本校的学生。不仅如此,美国学生主动提出问题、解决问题的热情,更是远远高于国内。

    因为对于州立大学来说,使用 matlab 仿真一个课程相关的内容,那往往只是一门课程的小作业要求(有时候作业的解释并不很详细),普通学生,不论是跟同学讨论、请教助教或者谷歌寻找相关的教程,还是会尽量自己独立完成作业的;而对于我们自动化的同学来说,这种东西只有大佬学霸才会,最多不超过百分之十的人会,往往就是拿着某几个大佬甚至是几届以上的代代传来应付作业(甚至还可以用一用万能的淘宝代做,这里就点到为止了,不能再传播这样教人学坏的方法了)。

    那么跟国内以前比怎么样呢?以自动化专业的控制系列课程为例,对比的对象主要是目前我的本科学校自动化从工程数学、信号与系统到控制工程基础、现代控制理论,与过去哈工大一位老师大约十年前的一门《控制系统设计》课程(我只看到了那门课的一场 45 分钟的节选)。

    如果是一个行家来分析我们的教学结果,可以说是有些可耻的:大多数学生学完了这几门课程了,由于上课时往往只是对着 ppt 或者课本讲几个例题(本质上只是算术题,连数学都不配称呼,因为缺少起码的技巧与思想),结果就是学生连傅里叶变换的内涵都不能理解,更不要说进一步推广到频谱分析等等应用上了,至于所谓课程之间的融会贯通,更是天方夜谭一般。

    反观哈工大这位老师的 45 分钟的课程录像,他简单的从波特图(bode plot)入手,从高低频分别讲解了设计的要点,并以自己从事的课题飞行器设计为例,提到工作频率大约在 20Hz 左右,随后又讲解了截止频率,并与模拟电路上的运算放大器之所以存在所谓 1MHz 这样的提法无缝衔接。

    这就叫深入浅出,不仅简明扼要地讲明白了问题的关键,还理清了各门课之间的关系,并能联系到工程实际。虽然这只是一门理论课,但是高下立判。

    跟一些老教授探讨后,他们都表示,二三十年前的课程,基本都能达到上述的那种深入浅出的要求。这也从微观上印证了市面上流传的所谓大学扩招后教学质量的严重滑坡这一论断。

    作为一个从事过科学研究类的脑力劳动工作的人,如果相信什么各种观点/事物都是各有所长,所以应该等量齐观/平等看待的观点,是可笑的,思想与境界就是有高下之分的,因为高观点可以包含低观点的内容,并解释说明其不能说明的内容

    为什么会这样呢?

    我们可以从世界名校斯坦福大学的成长历史来重新思考一下这个问题。

    二战后,斯坦福大学为了合理使用多余的校园土地(并获得一定盈利),租出了大量的土地给高新产业公司使用,这就是后来大名鼎鼎的硅谷的雏形。

    硅谷在大量人才、资本涌入后,几乎变成了全球高新技术的代名词;而斯坦福大学,也从那时一个建校才五十年左右的二流大学(当时哈佛、MIT 的获得的政府拨款都是上亿美元甚至十亿美元级别,斯坦福只有区区六百万美元拨款,还是用于培训教师的)一跃成为了如今世界上数一数二的顶尖大学。

    为什么会这样?《反脆弱》(Anti-Fragile) 一书中提到:现代教育带来的最大的错觉就是,以为产业的发展是因为教育带动的,实际上恰恰相反,教育是由产业带动的。

    1950年代,菲律宾的识字率是中国台湾的两倍,可从六十年代开始,(台湾也进行了所谓的十大建设)台湾的人均 GDP 以及各方面工业产业的发展,却远超过了菲律宾,这个优势一直持续到了今天(相反的,菲律宾大量的受教育人口,却带来了一个特殊产业—菲佣)。

    科学研究或许不完全依照这个规律,但是工程技术的发展,几乎都是靠产业带动的。

    举一个大家更熟悉的例子,华为在通信方面建树很大,它即使是给普通员工的薪资,在目前的就业环境中也是可观的。

    因此当前在中国,电子及其相关的专业是一个很热门的专业,中国的通信技术也是世界领先的;

    相比之下,生物学,生物虽然一度被吹嘘为所谓二十一世纪是生物的世纪,但是大量的中国生物毕业生,只能从事很低级的工作,薪资也很低,也便谈不上什么真正有意义的创新了。

    同样的事情在美国则不然,生物信息学,由于有很多创业公司的投资,是美国名列前茅的高薪资工作专业之一,美国的生物技术发展,也的确走在世界前列。没有脱离产业的所谓先进科学。

    无产业的所谓科学,往往不过是大量高影响因子的论文灌水,对国家甚至只是个人的发展,都是效益甚微的。

    那么回到教育上,我们也可以类似地得出结论:没有脱离产业的所谓先进教学,一切不结合工程实际的教学目标与教学方法,基本上都是空谈,劳而无功,严重脱离实际,教学的实际效果也很差。

    本文姑且不谈中国教育应该如何向这个方向改革,但是,个人在这样的教育环境下,应该树立怎样的发展自己的观点,还是值得探讨一下的。

    刚刚来到大学时,我也遇到过各种各样很常见的问题:大学究竟该学点什么不同于高中的东西?我应该怎么适应大学这种较为松散的教学、工作环境?

    另外当然就是顺便思考自己应该何去何从,也会经常在深夜辗转反侧,因为自己的无能为力而痛苦、愤怒,人最怕的不是辛苦,而是这种明知处于一种讨厌的状态,却无法摆脱的无能为力

    要想在各国现行高等教育下获得成功,或者更广泛一点地说,在当代越来越普遍的脑力劳动工作中取得成功,人必须得学会深度工作的能力(当然,也有人会把它通俗化说成所谓的学习能力)。

    也就是说,学会针对特定的智力问题,摆脱外界打扰,刻苦钻研、自我学习分析的能力。这个能力是抽象的,但是也是具体的。

    因为任何能每天专注工作思考自学很多个小时的人,对于大多数脑力劳动工作,都是可以很快掌握并熟练的,这就像一个大教授并不可能对一个新的研究方向感到完全束手无策一样,即使他可能以前从未了解过这个课题。

    这种对自己学习研究能力的自信,我觉得就是高等教育或者说素质教育,理应培养的内容。

    对于这个能力的培养,有一个小技巧:商品的价值来自社会必要劳动时间,所谓必要时间,就是无差别的人类劳动;把这个观点推广到学习,或者更一般的脑力劳动上,就是要学会统计自己学习的有效劳动时间。大家应该都有过这样的经历:当看书或者做题很投入的时候,仿佛世界上只剩下了自己跟题目一样,全神贯注,用中国话说叫有点物我两忘,用现代的理论说,叫进入了心流的状态。在这种状态下的学习效率是很高的,可能一两个小时,抵得上漫无目的乱翻书几个小时甚至一天。因此,统计自己是否工作,就必须统计自己的有效的工作时间,一般看来,八到十个小时大约是普通人的极限了,再多下去基本上很难维持集中力(当然,根据每天的精神身体状态也会产生波动),所以如果做到比如说八个小时,就问心无愧地回去休息吧,一张一弛,文武之道,适当的休息才能保证后续工作的连续有效率。

    当然了,对于我们做技术的人来说,光讲这些抽象的方法论还是不够的,如果具体到行为上,还是得落实到一些具体的技术上。

    我的一个学弟,说起来还是非cs科班专业的,早早就意识到会一门硬技术的重要性。于是,他从大一时就开始混迹各大技术论坛,于是开始从Linux操作系统上手,从基础操作、到编写相关的脚本、再到阅读理解分析底层源码,对于Unix/Linux的理解很早就远超同龄人了。下面是他的故事

    最初的故事还是从单片机开始的。

    进入大学两个月,学院举办采访班导师的班级活动。班导师说大家学习完 C++ 课程后可以去学学单片机。我记在了心里。

    大一第一个学期结束后的寒假,我凭借自己扎实的 C++ 基础学习了 C51 单片机,熟悉了使用 keil 软件的开发单片机的流程,了解了中断,定时,串口,I2C 总线,按键以及 LCD1602 液晶屏…由于了解到单片机也可以用汇编开发,所以顺道也学习了《汇编语言》, 甚至至今仍然记得书中的汇编程序do0

    学习完后寒假还剩几天,我闲来无事,上网看看有没有什么和单片机相关的,可以继续学习。在随意翻看网页时我看到了树莓派,于是马上入手了。

    从此,为了征服树莓派,我走上了 linux 学习的道路,期间不断学习 linux c 编程,python语言,bash脚本,mysql 数据库 … 期间做过很多好玩的开源项目,自娱自乐,也受到了一些已经工作了的技术人员的认同。

    直到大二上,对编程的过度关注影响了我的学业。我也开始怀疑自己编程下去到底对不对,毕竟一开始我只是想做硬件而已。所以当时暂缓了编程的进一步学习,重新投入到自己的专业课中。大二下在学习数电,模电以及信号与系统的过程中,我接触到了verilog 硬件描述语言与 fpga,便开始了我的数字生涯。大三在不断学习物理以及数学的空闲时间里,我自学了数字信号处理以及 systemverilog 验证,同时也做过一些相关的项目。

    尽管我的学业很顺利,自己凭借个人努力在大学中也学到了很多内容。

    但我一直疑惑,我自己要的到底是什么,甚至经常熬夜思考。

    直到有一晚上,我发现自己对探寻事物的本质有谜一般的兴趣。学习计算机语言,看 linux 内核的代码,学习数字逻辑以及物理学习都是我探寻事物本质的一些表现。所以我决定走上电子学和物理的道路。

    当我亲眼看到粒子加速器的那一刻,我有种感觉——这就是我想要的

    而且我觉得更有意思的一点就是,随着他几年的努力工作学习研究,他终于意识到自己的兴趣点其实在于研究更为底层的理论,目前已被某名校国家实验室录取,但是技术的成长不会背叛他,不仅在录取过程中让导师非常欣赏,并且在后续的研究工作中,也让他左右逢源,做什么事情都有自己的一套技术上的解决思路。即使不能直接用上,也能快速上手学习、应用一个技术达到一定程度,已经融入了他的血液中。

    独立思考与批判性思维的缺失

    其实,就技术谈技术,还是略显肤浅,毕竟授人以鱼不如授人以渔,实际上中国大学生普遍出现的通病就是做事被动:非要等老师、大佬说好才去做。此外,在社交方面,更是一个令人头疼的问题。很多擅长做技术的同学,对于搞人际关系,甚至是有点自傲的,觉得自己搞不好人际关系和是跟自己技术很强是互补一样。但是,作为一个优秀的人,成长应该是全面的,即使是为了做出更大的项目,寻找合适的人合作也是必不可少的,这点实在是很少有人能提及。

    这是一种陋习,而这个陋习不得不说很大程度来自我们的教育体系甚至于文化:中学乃至于一定程度到了大学,管理者们总是以一种颇为军事的想法来思考如何管理学生,简单来说就是听话,一切要为了高考。是啊,考纲既然已经如此固定,在教学体系下保证最大程度的人能得到更多的分数,自然是很难容得下一些刺头的,因为他们或许有一些才能,但是会破坏正常的教学秩序。在这样的教育要求下,即使一些很叛逆的人,也渐渐磨平了棱角,至于本来就没什么想法的人,就更有些不敢越雷池一步了。

    这种听话思维的延续,与一些诸如枪打出头鸟之类的文化结合,让人不要去乱想乱动。现在国家说我们需要专业人才,高考总体上却还是综合性的考试;我们需要创新性人才,可中学教育时往往又让学生不要违规,实在是有一点缘木求鱼的感觉。

    所以,要习惯于创新,就要敢想敢做,有鲁迅先生所谓拿来主义的魄力,敢于对一切想法进行独立而科学的思考。

    实际上,不仅是思考、做事,对于人际关系的发展,这点中国人大多要向美国人学习,当我第一天来到研究生学校时,我们第一天的课程居然是:教你如何使用领英,如何求职并进行 networking(我认为仅仅使用社交一词翻译似乎不太贴切,翻译为构筑自己的社会关系网似更准确)。正如面子之于中国人,social/networking 之于美国人也是一种家常便饭。他们教育人们要学会合理地结交有效的人脉,如果有志于相关方向的工作,就努力从亲戚、朋友、校友等等人处认识,完成一些原本只通过自己个人的想象不可能想到或者完成的事情。

    这点国内也渐渐开始有了这样的氛围,尤其是在商业环境下。但是,还不够。甚至在文化上容易受到钻营之类的诟病。这点就又是一种对人与人性的合理发展的限制了。只要不违反规则与道德,人应该积极努力地为了改变自己的命运而努力,我觉得这是无可非议的。

    对于还在高校内的学生也是,学校内往往也有科研训练、毕业设计或者纯粹地去加入一些知名教授的研究组从事一些科研或者工程工作的机会。如果能提前调查一下自己想研究的方向以及学校内教授们研究内容,大胆地写邮件或者用其他方式联系教授,也未必不能获得教授的指导和帮助,做出一些不错的工作来。或许在与教授的交往中,得到他的很多指导建议,从此又走上了一条更宽广的路,这种事情也并不鲜见。(小技巧,如果不清楚怎么找,也可以参考一下往年的优秀毕业设计名单等,往届能稳定带出成果的老师,往往较为擅长带学生)

    当然,校外也有各种各样的项目、实习、工作等等机会,重要的还是走出自己的舒适区,给自己新的挑战,有时候多逼自己一把,也许事情就成了,人生也就打开了新的局面。

    克服人性的劣根——人没有梦想,跟咸鱼有什么区别!

    上一部分说了那么多制度上的问题,只是希望大家能跳出圈子来看问题,并不是为了给大家一个我xxxx都是社会的错的印象,实际上,真正的大佬,那都是些出淤泥而不染的人物,而要想成为一个技术大佬,也得努力克服自己身上存在的各种缺点,努力使自己成为一个更好的人,而不是因为找到了一些客观理由就当做救命稻草,为自己的无能作借口。

    这个部分我们将着重于分析做好技术,个人的性格以及能力上重要的几个方面。

    执行力的培养

    执行力,在信息发达的当下,一定程度上已经变成了决定年轻人成绩的决定性因素了。因为很多人只是单纯去说xx技术好,我想学xx技术,然后学个两天,会打 hello world 就说自己学习过了,可是正如代码界名言 talk is cheap, show me the code 所表达的一样,水平没有真的提高,只是学会了几个术语,骗人可以,骗不了计算机的,总归真要用的时候是拿不出结果来的。

    对于这一点,弥补的办法主要是坚持知行合一 的想法,就是永远要在实践中检查自己做的事情是不是真的配得上自己吹嘘的内容。《传习录》中写道:人须在事上磨,方立得住,只有一次一次坚持把自己想做的事情落到实处,克服在这个过程中的厌恶、疲劳等等不利因素,才能在自控力上真正有点进步,能控制住自己的人,在有需要时,执行力自然高。

    当然,这方面也有一些小技巧,比如说把困难的(准确的说是思维上最困难的,就是最厌恶最害怕做的麻烦事,不一定实际上做起来是最难的)事情最先做,这样,就像势如破竹一般,不会让自己陷入一直在简单工作的舒适区中徘徊的窘境,而复杂任务的进度也就能保证了。

    当然,除了工作,适当地进行一些合理的享受,比如说欣赏音乐,或者参加各种体育活动,比起单纯地宅在家里,对身心意志健康的恢复,也自然会好很多。

    这里需要重点提一句,体育锻炼除了增强体质、磨炼意志以外,我觉得对人的精神状态也有很积极的作用,对培养一种阳刚、向上的精神面貌也大有裨益。实际上,儒家的六艺里射(射箭)、御(骑马)都是体育运动;而在美国各大高校,健身房也几乎遍地都是,健身的文化非常浓郁。显然,经常参加体育锻炼不只是只有增强体质这一看似肤浅的效果的。(实际上,经常锻炼带来的体力进步,也有助于集中力的提高,很多人表示,看书可能一天最多只能集中六个小时以下,我个人在大学期间经常长跑,体质也好了很多,集中力也明显地上升到了后来能看到 8-10 小时)

    执行力的提高,有一个心理误区是一定要克服的:同一个项目,他划水一点做,能得 85 分,我认真做,也就 88、90 分,有什么区别呢?无论什么样的进步,都是积少成多的,有时候分数虽然只是高一点,你对这个项目的理解的通透程度就是不一样的,或者你对这个技术能做到的一些边界条件、一些可能会在实际过程中出现的细节抓的很清楚,这样以后负责重大项目时,别人不行的东西,你行;别人做的不够完美的地方,你做的尽善尽美,这就是你的核心价值,一段升迁可能就源自于这么看似寻常的优秀:让这个人办事,稳重,放心,不需要太多的过问,省事,这不就是值得被拔擢的品质吗?

    此外,正如名著《高效能人士的七个习惯》所言,想提高自己的执行力,重要的是将自己的精力聚拢,多关心自己能改变的东西,把能量聚焦于可影响区,不要总是为了一些自己无力改变的事情去咸吃萝卜淡操心,一则是无用,只是乱想空发感慨,什么事也不会改变,一则是局外人、非专业人士对于相关的问题发表的见解,大多都是不准确甚至是完全错误的,如果总是把时间精力浪费在一些看似高尚实则跟自己无关的事情上,实际上反而影响了自己的不断进步以及本能期待的影响力、执行力的成长。

    技术眼光的培养

    这一点其实有点像做科研,对于一个技术领域,有条件的话,要搞清楚相关的技术的来龙去脉,有哪些技术路线,分为哪些派别,各个派别之间有什么优点和缺点,你更喜欢哪种,哪种更有可能继续发展下去?对于这些问题的回答,决定了你在相关的技术领域的深耕是否会在未来带来更大的价值。

    当然,对于新入门或者还没有摸到门道的人来说,最快的方法还是想办法获取业界大佬的有针对性的观点。其实很多人都是,会花很多时间去寻找xx技术的 好老师 ,殊不知比起某个专门技术的老师更重要的,是寻找一个真正能在各方面教育你的导师,这样的人,不仅拥有对于技术的品味,更重要的是,他们往往对于做事、认识这个产业乃至于世界都是自己清晰完整的三观,这些方面的学习才是更潜移默化的成长,从这样的大佬学习经验、思考、工作的方法,从长远来看,才更有可能产生更加脱胎换骨的变化,而不仅仅是学到某一特定技术。

    当然,做技术跟搞科研,甚至搞艺术是没有本质区别的,都是对未知、对真理的一种探索,永远都应该保持对于技术的热爱与敬畏。因为热爱,所以永远充满了学习的热情;因为敬畏,所以永远不敢以自己知道的小小一隅而自满自得,觉得自己不需要再学习了,殊不知技术的迭代与进步,实在是快到短短几年之间,就有可能发生整个观念上的改变的情况,如果不能 stay hungry, stay foolish ,则实在是很容易被淘汰掉。

    就个人的进步而言,技术能力的培养可以来自两个方面,一则是在工作岗位上努力解决技术上的瓶颈、难题,另一则是在高校中通过接受正规的科研培训,提高自己分析、解决问题的能力。

    先谈工作岗位,我看过一些技术大佬回忆自己的成长故事,除了极少数天才,大多也并不是一开始就天赋异禀或者说仅仅看看书、学学理论知识就超越常人的。但是他们回忆起自己成长的经历时,大多都是从回忆公司的项目开始的,比如说之前看一个腾讯大佬的回忆,就是进厂时被要求用纯 C 语言写一个能运行的并发服务器,其中不允许直接使用已经写好的框架,必须一点点自己查底层的内置标准库;后来是解决一个更大的服务器配置、优化的升级,于是他仔细阅读分析过去的源码,在看过去的大佬代码中学会了很多设计思想,然后实现了这个项目……在完成这些项目之前,其实他的水平也就跟一般人差不多,即使是完成之后,在某些细节知识体系等等上,他可能依旧是不如很多人的,但是这就是实践的魅力了,实践会逼着你删繁就简、直击要害,其实很多人还是有太多的学生思维,觉得很多事情不学个通透就不想、不敢着手去做,其实很多时候,有个大概理解,针对一个具体问题不断去调查、钻研、学习,才是更本质的、更迅速的能力,而且会逼着你把看似不相关的知识融会贯通,否则也就不能形成问题的体系了。

    再讲讲正规的科研培训,实话说,中国除了少数名校或者知名研究组,大多在科研培训这块是很不如美国高校的。当然,这可能也与国内很多科研还是盲目跟风、关注的更多的是国际上 SCI 发表的情况有关。而在美国,很多论文的发表,需求往往出自一些公司,所以研究的结果经常能有直接的应用和衡量标准,从而较不容易陷入自嗨的境地,只是自己做一些理论结果。

    而落实到个人,虽然在学校中做的内容,如果不是读博士、专业从事相关内容,大多数人实际上毕业后很难直接做到与自己的研究直接相关的工作。但是,这是不是就是说,认真研究就不重要呢?我觉得也不是,科研本质上是培养一种符合科学范式的工作、研究方法论。比如说,初到一个新的领域,如何调查、分析这个领域的发展情况,研究兴趣,是否有进一步研究的价值;对于一个问题,如何寻找不同的研究切入方法;对于一些方法,如何合理地进行批评与改进,等等等等。这些都不是一朝一夕就能学会的,都得在长期的工作中反复打磨,才能越来越提高自己的思考、研究能力。

    其实,以代码为例,我认为计算机科学的进步很少有什么特别巨大的跃进,真正核心的理念其实也就那么多:比如说操作系统、算法等等,框架虽然会不断地在之前的基础上进行改进,但是创新不是一拍脑袋就能出现的,它总还得符合基本的原理,比如说谷歌的著名分布式框架 MapReduce,原理上还是用了一个分治法的思想。在学习的过程中,不满足于知识本身,更多地探究其为什么能想到、还能在其他地方怎么灵活运用,你也可以成为下一个化腐朽为神奇的创新者。

    内驱力的培养

    上面讲了很多热情相关的内容,这种热情其实就是所谓的内驱力,就是由人的思考、信念产生的驱使人不断克服厌倦、疲劳去克服一件件困难的精神。内驱力不足,归根结底是自己缺乏深厚的文化或者情感积淀而成的信念。

    不过,人的意志力也的确是有限的,指望人能一直靠某个信念或者想法驱动自己,也实在是很难的事情,对于这个问题,主要的弥补办法是:读好书以及交益友,好的书籍往往都是各方面建树很大的大佬写出的充沛了各种信念与思考的产物,益友一般来说就是那些理想信念坚定、能力很强的人,人说起来是复杂的动物,但是有时也并不那么复杂,比如说人总归会下意识地模仿身边人的行为,因此如果朋友们都努力工作、积极向上,一个人也实在很难长时间保持很颓废的状态,这就是益友带来的好处了。

    在这里,我想讲一个我个人认为很正确的信念,这也是无数中国古籍、无数仁人志士们都信奉的观点君子不器

    所谓的,往往被解读为出人头地,因此家长们对孩子的期望都是成大器,本身自然没什么大问题。而且,如果不能成器,人往往在社会上不能得意,甚至连亲朋故旧的尊重往往都得不到。但是其实器也可以不这样理解,器的意思是不被一切世俗的规则与思想所奴役,获得不受约束的自由。(这与无数程序员羡慕的财务自由梦想在一定程度上是同义词)

    自由永远是一把双刃剑,人不受各方面的约束,就容易堕落,容易为物所役,贪腐挥霍,整个人就堕落下去了。所以,虽然不器不是无器(不成器),但是如果沉迷于器,即使成了大器,之后也必然堕落为小人,心中永远要有对真理、对正义、对社会公正的那种良知,对还在遭受苦难的不幸的人们的怜悯,得到了要施于人,学到了要教给人,这样的人,才能得到人们真正的尊重,也才真的实现了人的自我实现。

    其实,只有心中有这种不能割舍的热爱的人,才能不以物喜,不以己悲,在一次次失败与低谷中,不以个人的得失为意,坚持自己的信念,修身以俟,夭寿不二,达到那个理想的彼岸。

    人的发展本质上是非线性的,这种让人无法预测的伟大进步,才是人类与人性真正伟大而令人感动的地方,也是教育真正可贵的地方。

    即使是一个很无知很粗鄙的人(实际上,大家在很小的时候不都是这样的吗),如果寻到正道,努力修养锻炼自己数年,完全有可能变成一个有文化有思想有能力的充分发展的人才。

    我觉得一切理想主义者的本质就是相信人类与人性的可能性,相信即使在无常的命运与世界中,人作为整体,总有一些个体,能与其不确定性抗争,并成长到可以面对命运、认清命运、抗击命运,而作为共同承认的一些信念,也就在这些人身上得到了传承,这也是教育最可贵的地方

    虽然谁也不能说种下的种子一定会发芽成大树,但是谁又能说种下的种子就一定不可能发芽成参天大树呢?

    人真的是一种一加一加一就能等于一百的动物,对自己、对身边的人都充满这样的信念与希望吧,人生的美好、人性的伟大,不也正在于此吗?

    结语

    本文字数虽长,但是都是长期思考的结果,不过鉴于很难一次性读完全部的要点,这里再做一次简要总结:

    1. 阅读书籍是与伟人们对话的过程,也是理解他们如何认识世界、改造世界的过程。从书籍中可以汲取他们的思想,领悟他们的品格,找到自己的定位,并指导自己的行为。

    2. 学会自省,构建自己的信仰价值体系,为自己真正需要坚守的价值燃烧自己的生命

    3. 机会总会到来,但是更重要的是在日常生活中关注细小的事情,不要老是做低快感阈值的事情,要多做一些具有长期价值的要事,克服行为成瘾

    4. 学会真正的深度工作的方法,提高自己工作的效率与产出

    5. *独立思考、独立思考、独立思考!再怎么强调它的重要性也不为过

    6. 走出舒适区,与更大的世界建立联系

    7. 人须在事上磨,方立得住

    8. 积极投身实践,在实践中抓住做事情的要害

    9. 君子不器,先成器再不器

    10. 相信人类与人性的可能性,发自真心关爱别人的成长

    如果没有读出上述这些观点的,可以返回前面,再看一看,思考思考。

    两年前,我偶然读到《不做空心人》这篇演讲稿,文中的那种慷慨激昂的意气让我非常感动,读到之后,我甚至专门找了个本子,提笔把这篇文章工工整整抄了一遍。这里,我也想摘录几段我非常喜欢的句子(建议自行搜索全文):

    越是在众声喧哗中,越需要一颗真正安静下来的心。越是快速变化的时代,越需要一颗真正慢下来的心。

    世界上所有的美,都需要一种高度的专注和漫长时间的淬火。读书、求知,当然更不例外。有过乡村生活经验的人知道,长得过快的树,是空心的,其材质不堪大用。

    在时代的屏幕上瞬间自生自灭的文字,越是浅陋粗鄙,就越需要有人能以坐得十年冷板凳的勇气,舍弃眼前之利、萤火之光,创造出能昭示一个时代良心和品质的精神产品,穿透这个时代流传下去。

    越是有人觉得心里空荡荡的,就越需要另一群人懂得,应该往这种空荡荡中填补些什么

    越是有人不再确信什么,觉得爱、理想、信仰成了过时的、陈旧而虚张的概念,就越是需要另一群人把这些词,高高地举在头顶。对内心贫乏的人来说,这些词是空的。而对内心丰富的人来说,它们永远是有血有肉的,是新鲜的。

    要把求知、求学上的怀疑精神,与对生命价值的确认和信仰的形成融为一体。把对科学的冷眼观察、冷静探索,与做人做事的古道热肠融为一体。把探求真理的坚韧不拔,与生活中怜小怜弱、恤残恤孤的生命柔情融为一体。只有这样一颗有所爱的心,才不会空掉。我们才不致沦为一个空心人

    世界上所有的美,都需要一种高度的专注和漫长时间的淬火。读书、求知,当然更不例外。有过乡村生活经验的人知道,长得过快的树,是空心的,其材质不堪大用。

    在时代的屏幕上瞬间自生自灭的文字,越是浅陋粗鄙,就越需要有人能以“坐得十年冷板凳”的勇气,舍弃眼前之利、萤火之光,创造出能昭示一个时代良心和品质的精神产品,穿透这个时代流传下去。

    越是有人觉得心里空荡荡的,就越需要另一群人懂得,应该往这种空荡荡中填补些什么

    越是有人不再确信什么,觉得“爱”、“理想”、“信仰”成了过时的、陈旧而虚张的概念,就越是需要另一群人把这些词,高高地举在头顶。对内心贫乏的人来说,这些词是空的。而对内心丰富的人来说,它们永远是有血有肉的,是新鲜的。

    要把求知、求学上的怀疑精神,与对生命价值的确认和信仰的形成融为一体。把对科学的冷眼观察、冷静探索,与做人做事的古道热肠融为一体。把探求真理的坚韧不拔,与生活中怜小怜弱、恤残恤孤的生命柔情融为一体。只有这样一颗有所爱的心,才不会空掉。我们才不致沦为一个空心人

    谁的青春不迷茫呢?迷茫大概是无可避免的情况,但是就像鲁迅所说不满足是向上的车轮,重要的是不抛弃、不放弃,在逆境时的坚守,就像《周易》中所谓潜龙勿用,假以时日,也总有飞龙在天的一天。

    借用一句诗词风物长宜放眼量,事情总会慢慢起变化的,朋友们,勉之!

    展开全文
  • 8000字干货:那些很厉害的是怎么构建知识体系的

    万次阅读 多人点赞 2019-09-29 11:18:27
    分辨知识知识体系的差别 理解如何用八大问发现知识的连接点; 掌握致用类知识体系的构建方法; 能够应用甜蜜区模型找到特定领域来构建知识体系。 1. 知识体系?有必要吗? 小张准备通过跑步锻炼身体,可因为之前...

    本文约8000字,正常阅读需要15~20分钟。读完本文可以获得如下收益:

    1. 分辨知识和知识体系的差别
    2. 理解如何用八大问发现知识的连接点;
    3. 掌握致用类知识体系的构建方法;
    4. 能够应用甜蜜区模型找到特定领域来构建知识体系。

    1. 知识体系?有必要吗?

    小张准备通过跑步锻炼身体,可因为之前听说过小腿变粗、膝盖受伤、猝死等等与跑步有关的意外状况,有点担心自己会掉进各种坑里,就在微信上问朋友圈一直晒跑步里程的朋友老安。

    小张问老安:“老安,我想跑步,有什么要注意的没?”

    老安回答:“注意跑姿就行了,要前脚掌先着地,不然容易损伤膝盖。”说完还给小张发了张片。

    小张大喜,心想,幸亏问了老安,不然膝盖就废了。

    第二天早上上班,小张碰见一个部门的黑子,想起来黑子前段时间说他参加了什么夜跑团,就问黑子:“黑子,听说你参加了夜跑团,跑步经验肯定很丰富了,我最近也想跑步,担心跑出问题,给点建议怎么样?”

    黑子说:“建议嘛,的确有一条啊,别轻信网络上各种文章说的什么脚后跟先着地容易损伤膝盖应该前脚掌先着地之类的话。你知道吗,我参加的夜跑团里,有很多经验丰富的跑者,他们说呀,80%的马拉松跑者跑步时都是后脚跟先着地。人家跑那么久那么远都没事儿,就说明,脚后跟先着地是正确的选择。”黑子说着,拿出手机,找了张图给小张看。

    小张边看图边说:“有道理,有道理,还是黑子专业。”可他心里面却犯嘀咕,怎么回事儿啊这是,老安和黑子,说的完全是相反的。

    小张决定找一位资深的跑者问问,想来想去,想到他的大学同学飞将军,他常年跑步,全马都跑了6次了,最近好像还开发了一门如何跑步的课程。于是中午吃饭时,他用微信发了条消息给飞将军:“飞将军啊,我最近有点想跑步,你是专业的,给我点建议,怎么跑比较好呢?”

    过了一会儿,飞将军发过来一条消息:“你先回答我几个问题:1)你是想跑马还是慢跑锻炼?2)你身高、体重、体脂率各是多少?3)体力如何?4)有没有心脏病、高血压、头晕等情况?5)有没膝关节受伤、腰椎间盘突出等情况?6)准备在哪里跑?塑胶跑道、跑步机、水泥马路还是别的?……”

    小张一看飞将军连珠炮式发出的12个问题,不禁叫了一声“天呐”。

    好啦,现在请你回答一个问题:老安、黑子和飞将军,这三个人,哪一位更专业?

    如果我没猜错,你的答案和我一样:飞将军更为专业。

    为什么呢?

    因为飞将军没有像老安和黑子那样直接给一个前脚掌先着地或脚后跟先着地的建议,而是先望闻问切,从各个方面了解小张的情况,然后才给出适合小张的建议。

    那为什么他能够做到这一点呢?

    因为飞将军在跑步这个领域,拥有丰富的知识,涵盖跑姿、配速、相关疾病、路面、心率等等,这些知识有机地结合在一起,形成了一套知识体系,能够从多个维度综合评估一个人该如何开始跑步、如何进阶。

    不仅仅跑步这个领域有知识体系,各个领域都有知识体系,我们生活中遇到的大部分问题,都可以找到一个围绕着它形成的知识体系。

    针对某个领域、某个问题的知识体系,对我们有非常多的好处,典型的有三类:

    1. 表达能力升级。这是因为构建知识体系的过程,会用到并培养成长思维、批判思维和系统思维,提升思考能力。当我们能够把一件事情的逻辑、层面、各个维度想明白,就能讲明白。
    2. 从零到一成为专家。知识体系是结构化的,知识点之间彼此关联,有无数回路,四通八达。这样的好处是,我们遇到一个问题,就会触发某个知识点,我们捕捉到这个知识点,就可以沿着知识体系的无数关联和回路,快速找到相关的其他知识的点,组合起来,形成针对所遇到问题的解决方案,就表现出专业水准,就当得起“领域专家”之称。
    3. 智慧影响待人接物。知识内化,形成体系,吐故纳新,不断进化,我们的智慧就会跟着升级,就能应用于实际生活。一方面知道的越多越能体会知识无涯越会虚心、包容,越能与他人和谐相处,另一方面体系越完善越能帮助自己和他人解决问题,促进彼此关系。

    举两个例子对比一下,我们马上能感受到拥有知识体系的好处。

    医生D1,接诊一位大腿中箭的士兵,马上想到:“中箭了就得赶紧拔出来才好。”于是他一顿操作猛如虎,拔掉了士兵屁大腿上的长箭。不料鲜血迸出,他赶紧找来一团棉花,一条线绳给士兵包扎上。然后拍拍手,告诉士兵,长箭已除,万事大吉。

    医生D2,也接诊了一位屁股中箭的士兵,他没有立即动手拔箭,而是先问了士兵中箭的详情、各个身体部位的感觉、以往的箭伤治疗史等等情况,然后准备了清洗、消炎、包扎要用的各种物品,接下来消炎、拔箭、敷药、包扎,最后又叮嘱了饮食禁忌、日常护理、活动建议、复诊、常见并发症和应对策略等等事情,才结束治疗。结果这位士兵很快痊愈了。

    D1缺乏诊治箭伤的知识体系,脑中只有几点零散的知识,只会头痛医头脚痛医脚,想不到感染、发烧、饮食禁忌等事情,结果他的病人回去后,伤口感染、化脓,引起各种并发症,后来救治无效,含恨离世。

    反观D2,因为有知识体系,能够系统的、多维度的、多环节的考虑各种问题,妥善制定箭伤医治策略,他的病人得到了很好的诊治,很快就痊愈了。

    医疗领域的知识体系,可以治病救人,效用立竿见影。其他领域的知识体系,在处理该领域相关的问题时,也有类似的效果。我们的工作和生活中,就能找到很多例子,你不妨回想一下自己过去的经历,找一件事能够说明知识体系作用的事情出来,这样能加深我们对知识体系重要性的理解。

    2. 善用八大问发现知识的连接点

    从跑步和治病这几个例子中,我们可以看到,知识点是一个一个的,散乱的,比如“跑步时前脚掌先着地不伤膝盖”、“中箭后要赶快把箭拔出来”,就像我们小时候玩的木质积木。

    而知识体系是某个人结合自己的问题和实践形成的知识集合,知识点之间彼此以形式多样的方式关联,形成了特定的结构。比如飞将军关于跑步的知识体系,就是由跑姿、配速、跑量、心率、常见相关病症、跑鞋、路况、饮食等知识点相互链接而成。这样的知识体系,像我们乐高积木搭起来的建筑物。


    那么,现在有一个问题:用我们前面图片中的木质积木,可以搭建出上面的积木房子吗?

    估计我们的答案是一样的:不能。这也是为什么传统的木质积木无法风靡的关键原因——很难搭建出有稳固的、有创造性的东西,不耐玩。

    那为什么乐高积木就能够搭建出种类繁多、形式各异的“建筑物”呢?

    请大家看一下乐高积木的积木块:


    发现它们和传统积木块的不同了吗

    对,它们上面有很多凸起的圆点点!这些圆点点非常关键,它们可以嵌入其他积木块预留的凹槽,把两个积木块连接起来。

    也就是说,乐高积木块上有连接点,所以可以彼此连接,拼搭出各种具有稳定结构的“建筑物”!

    把知识比作积木块,如果知识上生出连接点,就也可以彼此连接,构建出适用于特定领域和特定问题的知识体系

    那么问题来了:知识有连接点吗?

    答案是肯定的,因为在各个领域都存在知识体系,知识体系是由若干知识榫合而成,知识要彼此榫合,就一定有连接点。

    知识本身就有连接点,而我们无法利用这些连接点构建出知识体系,往往是因为:我们没有发现连接点。就是说,连接点原本就存在,只是我们没看到。

    进一步说,只要有办法找到并标注出知识的连接点,散乱的知识就可能彼此连接成一个体系。

    那么问题来了:如何找到知识的连接点呢?

    拆书帮的创始人赵周老师,在讲如何将移动时代手机阅读到的信息转化为知识时,总结了一个结构化的方法,叫“八大问”。我们可以借助“八大问”,来分析信息、观点、事件、经历等,从中整理出知识和连接点。

    我们先介绍八大问,然后来看怎么使用它来挖掘知识的连接点。

    八大问是一个提问的框架,将针对信息、观点、事件、经历等的提问,分为“前、因、后、果,适、用、边、界”八类。

    这八类问题,可用来分析或整理信息,把信息变成知识,并找到知识的连接点。八大问又可以分为两组,前因后果和适用边界,前因后果用于分析信息,适用边界用于整理信息。

    为方便记忆,赵周老师找了八个成语帮助我们,前对应前车可鉴,因对应相因相生,后对应以观后效,果对应自食其果,适对应适得其反,用对应使用条件,边对应旁敲边鼓,界对应楚河汉界。

    赵周老师针对每一大问,都提供了几个典型问题,帮助我们理解和使用这一问。具体来讲,是这样的:

    • 前(前车可鉴):1)为什么这件事对我重要?2)他是怎么引出这个信息的?
    • 因(相因相生):1)作者提出了哪些关于原因的假设?2)怎么验证或排除这些假设?3)还有其他可能性吗?
    • 后(以观后效):1)若已从信息去做之后会怎样?2)对我的好处(效用)是什么?
    • 果(自食其果):1)不这么做的后果是什么?2)不改变的问题有多严重?
    • 适(适得其反):1)有没有相反的观点?2)有没有不支持这个的实例?
    • 用(使用条件):1)要这样做,需要具备哪些条件(考虑成本收益、态度、能力……)?2)这件事可以用什么其他方式来完成?
    • 边(旁敲边鼓):1)从前有没有类似的(或乍看起来差不多的)信息?2)其他领域/行业/人如何解决类似问题?
    • 界(楚河汉界):1)无论是相反的还是类似的信息,和这个信息的真正区别是什么?交界在哪里?

    在使用八大问时,不一定要原模原样的问赵周老师给出的示范问题,可以在理解这八类问题的前提下,针对具体情境,提出适合的问题。也就说,八大问最重要的是提供了一种提出有洞察力的问题的框架,这是它的意义所在,如果你有能力,可以领会心法,保持心法不变,提出新的问题,如果一开始不知道怎么用,则建议直接使用示范问题或在其基础上做变化。

    现在,我们举个例子,演示一下八大问的用法。

    小薇热情、活泼、健谈、点子多、标新立异、夸张、情绪波动大,她从事保险销售,业绩很好,领导安排她开发一个内部课程,给大家讲讲如何发展客户、维系客户。小薇答应两天搞定讲义,然后给大家讲。她动作很快,马上就开始写PPT,可总是被各种事务打断,一会儿有客户打电话,一会儿微信上有人咨询,一会儿又要出去见客户签合同,一会儿有同事请教,结果一个星期过去了,PPT只有一页标题。

    领导问小薇了两次次,什么时候可以讲,小薇都说太忙了,PPT才刚开了个头,一直没找出时间做。第三次的时候,领导皱着眉头给了小薇一个建议:“小薇啊,你时间管理能力还有很大提升空间啊,建议你好好学习下史蒂芬·柯维的时间管理四象限,把手头上的事情理一理。”小薇连忙称是,开始学习时间管理四象限。

    熟悉这个场景吗?你我的时间管理学习之路,基本上都是这么开始的。

    这种模式,其实也是我们切入一个新领域时的模式:遇到一个问题,要解决,就要用到新的知识、新的技能,开始学习之路,慢慢在实践中积累这个领域的知识。

    但是,我们积累的知识,能否形成体系,却依赖于我们能否做到“发现知识的连接点、主动链接不同的知识”。

    不管以前我们做得怎样,现在我们可以使用八大问来加速这个过程。

    让我们再次聚焦小薇的问题,看看怎样应用八大问来发现知识的连接点。现在,小薇知道了一个时间管理的方法,叫作“时间管理四象限”。

    先问“前”,这里小薇可以问“为什么掌握时间管理四象限对我很重要?”,答案可能是“做好时间管理,能帮助我合理安排任务,找到完成讲义开发的时间。”所以,学习时间管理四象限是有必要的。

    再问“因”,领导让小薇学习时间管理四象限,他提出了什么关于原因的假设呢?答案是“小薇时间管理能力欠缺,不能合理安排各种事务。”领导认为小薇只要管理好时间,就能抽出时间来完成PPT。这个假设正确吗?这是小薇没能在两天内完成讲义的唯一的原因吗?不一定哦,小薇没有完成PPT,除了时间管理的缘故,还有一个很重要的原因,是她内心不觉得“开发课程传授经验”这件事有多么重要,在她看来,最重要的事情是搞定客户赢得保单。

    接下来问“后”,小薇可以问“学习时间管理四象限对我的好处是什么?”她对照着时间管理四象限图,翻看《高效能人士的七个习惯》,很快想到了好处:聚焦要事,从容工作,提高工作质量和产出。简单讲,要事第一,提高工作效能。

    然后问“果”,直接用赵周老师的示范问题,“不这么做的后果是什么?”后果很明显,课程的交付时间会一再拖延,领导会认为小薇不重视自己的工作安排,甚至会怀疑小薇别有用心,进而影响小薇后续的工作开展,甚至影响升职加薪。所以从这个角度看,小薇需要尊重领导的工作安排,尽快搞定这项任务,所以她还是有必要学习时间管理。这样分析,小薇发现了一个点,某些工作任务的重要性,取决于领导的看法,所以她还应该学习目标管理、向上管理。

    再接下来问“适”,小薇问了自己这个问题“有没有人学了时间管理四象限却还是安排不好工作?”她马上想到同事小兰,曾经学习过时间管理四象限,可现在依然是每天忙东忙西丢东忘西经常出状况。

    然后问“用”,小薇可以这样问:“使用时间管理四象限的前提条件是什么?”经过研究,小薇发现,史蒂芬·柯维是一名企业管理者,同时也是为企业负责人提供咨询的人,他提出的时间管理矩阵,更多是针对管理者的,因为管理者有更多的掌控感和自由度,能够决定某件事情是否重要,进而根据紧急性来判断是立即做还是规划时间做。而像她和小兰,都在执行层面,多数时候无法决定一件事情的重要性,而不能判别重要性,就难以应用时间管理四象限。这也是小兰学了时间管理四象限依然工作忙乱的一个原因,同时也是她的领导觉得时间管理四象限管用的原因。这样一想,小薇知道了使用时间管理四象限的两个前提条件:1)个人具有分辨事情重要性的能力;2)个人对事情具有一定的掌控性和自由度。

    接下来问“边”,小薇先问自己“有没有与时间管理四象限类似的时间管理方法?”小薇一搜索,发现时间管理方法很多,GTD(衣柜整理法)、番茄工作法、三只青蛙、日历、猴子法则、Unbroken Time、思维导图、黄金工作时间……全都和时间管理有关。她一一搜集相关信息,进一步了解这些时间管理方法。接下来她又想到,管理时间其实是为了管理工作任务,那关于任务管理,有哪些方法呢?她一搜索,发现了看板、思维导图、80/20法则、清单、OKR、SMART法则等。

    最后问“界”的问题,“时间管理四象限的适用情况是什么?”小薇觉得,时间管理四象限,更适合这两类人:1)管理者;2)可以在一定范围内自我安排工作任务和时间的人。

    经过一轮八大问,小薇对时间管理四象限的认识更深入了,管理者、任务管理、时间管理、重要性、向上管理、要事第一、工作效能、工作自主度、规划……这些关键词留在了她的记忆中,成了可以与其他知识链接的连接点。

    八大问的目的,正是帮助我们从不同角度、维度来分析和整理信息,加深我们对知识的理解、认识,进而帮助我们为知识建立各个层面、各种角度的连接点,有了这些连接点,知识点彼此之间更容易产生关系,知识也更容易被外界问题刺激、唤醒。

    3. 如何构建知识体系

    一旦我们标注出知识的连接点,就可以把具备可连接性的两个知识经由连接点链接在一起,围绕着不同知识的不同类型的连接点,持续地、反复地执行这个操作,就可以慢慢形成知识体系。

    我们以小薇为例来说明这个过程。

    前面我们通过八大问中的“界(楚河汉界)”这一问,找到了“时间管理四象限”这个知识的一个连接点——管理者,即时间管理四象尤其适用于职场中的管理者。

    假如小薇在检索时间管理方法时,搜到了“猴子法则”,买了一本书叫作《别让猴子跳回背上》,学习了一下,运用八大问做了分析,画出了猴子法则和它的连接点,如下图所示:

    对比时间管理四象限的连接点和猴子法则的连接点,可以发现,通过“管理者”这个连接点,就可以把两者链接起来。

    假设小薇要考取中国寿险理财规划师,需要持续的看书学习,可她看书时总是分神,无法专注,于是就向一位特别爱看书的朋友请教如何才能专注看书,朋友告诉她使用“番茄工作法”,她了解了一下,发现番茄工作法是弗朗西斯科·西里洛上大学时为了专心学习发明的方法,特别适合看书学习这类伏案工作,她接着用八大问分析,画出了番茄工作法的连接点,如下图所示:

    番茄工作法属于时间管理领域的方法,那它就可以通过“时间管理”这个连接点,和时间管理四象限链接起来。

    随着小薇不断践行时间管理,了解到越来越多的方法,于是她就慢慢形成了时间管理方面的知识体系:

    现在可以看到知识体系的完整构建过程了:我们基于一个场景(问题),找到一个知识,运用八大问分析,挖掘各式各样的连接点,在持续实践中接触新的知识,反思回顾,把新知和旧知经由含义相近的连接点链接起来,形成体系。

    这个过程用文字来描述,只需要几百个字,阅读只需两三分钟,于是你可能会想,构建知识体系原来这么简单这么快呀,我很快就能搭建出自己的知识体系。实际上并非如此,知识体系的形成,是在生活实践中,不断解决问题,不断反思经验,不断发现连接点,不断链接知识,慢慢完成的,决不是一朝一夕之功。

    比如小薇从时间管理四象限链接到猴子法则,只有在她当了管理者,深受下属抛给她的猴子之苦时,才可能真正用到猴子法则,才能真正完成链接。这个过程,时机不成熟,就不会发生,所以看似简单的一个链接,分分钟的事情,实际上可能需要一年、两年,甚至三五年。

    经过实践和时间的考验,我们构建出了某个领域的知识体系,是不是万事大吉了呢?

    非也!

    我们还需要不断更新迭代自己在某个领域的知识体系,因为时代在发展,环境日新月异,问题层出不穷,用于解决问题的知识也会因之而快速演变。

    比如老韩是PPT设计师,对PPT 2016非常熟悉,各种功能了然于心,可2019年初Office 2019发布后,他就需要更新自己围绕着PPT 2016构建出来的知识体系,如果不这么做,遇到客户提出的特定于PPT 2019的问题,就没办法解决。

    比如小卢是增粉达人,原来微博微信的各种增粉策略、方法、实践,了然于胸,专门为各类自媒体团队提供增粉服务,现在短视频大火,抖音崛起,迅速成为国民级应用,那小胡就需要迅速学习基于抖音平台的增粉策略,包括抖音的推荐规则、封杀原则、内容分布、流量特点、视频结构等等,只有这样,他才能继续我他的客户提供有价值的服务。

    幸运的是,不管环境如何演变,只要我们掌握构建知识体系的方法,挖掘出新知识的连接点,就可以将新知识纳入既有知识体系,继而知识体系就可以获得更新,我们就能借助既有知识体系的势能,在新的领域打开局面。

    4. 在哪个领域建立自己的知识体系

    前面我们着重介绍了八大问发现知识的连接点、用连接点链接不同知识构建知识体系,并反复强调,拥有知识体系,可以专业、系统、全面、多维度的看待问题,创造难以复制的价值。

    现在,有的小伙伴心头可能会升起一个问号——“既然知识体系如此重要,那我是不是要在生活中的每个领域都构建出知识体系呢?”

    非也非也!

    我们不可能在每个领域都搭建一套知识体系——我们没那么多时间和精力。同时,也没那个必要。

    请想象如下场景:你发烧了三天,不见好转,头疼、浑身无力、骨肉疼痛,无法工作。

    你会怎么办?

    去研究关于发烧的各种知识、构建出发烧的知识体系,然后把自己治好,还是说,去医院,花钱让医生帮忙看病?

    你选的是去医院看病,对吧,很明智的选择。这也是我们面对多数领域问题的最佳选择——付费请目标领域的专业人士帮助解决。

    多数领域的问题,都可以外包给他人来解决,我们不用费尽心力在各方面都成为拥有强大知识体系的专家。

    我们要做的,是找到自己的根据地,发展出自己的知识体系,用自己的知识体系创造价值,交换其他领域的专业服务。

    那么,问题来了,怎么确定想要建立知识体系的领域呢?

    下面三个问题,提供了一个定位框架:

    1. 我擅长什么?
    2. 我爱好什么?
    3. 这个世界需要什么?

    这三个问题对应答案的交集,就是我们构建知识体系的甜蜜区:

    请反复探寻,找到自己的甜蜜区,锚定它,投入时间和精力,在实践中将各种知识融会贯通,构建出知识体系。

    最后,问个问题:现在的你,拥有(或打算构建)哪个领域的知识体系?欢迎留言和我分享_


    新上线了一门视频课程——程序员面试宝典,金九银十招聘季,想找工作的你,可以来看看!程序员面试宝典

    展开全文
  • 机交互基础教程

    千次阅读 多人点赞 2020-09-15 20:12:44
    机交互:Human-Computer Interaction HCI:关于设计、评价实现供人们使用的交互式计算机系统,并围绕相关的主要现象进行研究的学科 狭义:研究与计算机之间的信息交换: 到计算机:借助键盘、鼠标、操纵杆...
  • mac苹果电脑的颜色反转显示即视力障碍模式如何开启mac苹果电脑的颜色反转显示即视力障碍模式如何开启 Mac苹果电脑对视力障碍的人群来说并友好,这时候我们就需要开启颜色反转显示即视力障碍模式,那么如何开启呢?...
  • 为什么现在看好 CV 方向了呢?

    千次阅读 2021-01-19 12:35:09
    前者就是各种大佬,既能够提出好的idea,又能够解决实现idea的各种问题,刚开始idea一定work需要不断调整,另外很多东西没有现成的轮子需要自己实现。因此理论能力工程能力都要具备。后者一般.
  • 机交互知识 理论篇1

    千次阅读 2020-05-07 17:05:19
    eTable 作为新一代的机交互产品,具有良好的机交互界面,可以提供良好的机交互环境,在欧美已经逐渐应用于日常生活中,可以通过etable进行网上购物,进行游戏比拼等,是一个集成了各种感应组件的,类似于多...
  • 一位北美 IT 技术教你如何破局

    千次阅读 多人点赞 2020-02-24 23:31:02
    我对于本科时光的印象,还停留在那所普通 211 大学的建筑物之间,我坐在大学的时光长廊里,满眼望去,都是经历的过的故事。可毕业后回首,却很少有能说,自己从来没有迷茫过。...
  • 网络是新生事物,许多接触就忙着用于学习、工作娱乐等,对网络信息的安全性无暇顾及,安全意识淡薄。 3.网络安全投入有限,由于种种原因,软硬件投入有限,由此直接导致网络安全性降低。 网络与信息安全现状...
  • 进入其感应范围则输出高电平,离开感应范围则自动延时关闭高电平,输出低电平。 ②光敏控制 (可选) 模块预留有位置,可设置光敏控制,白天或光线强时感应。光敏控制为可选功能 ,出厂时未安装光敏电阻。如果...
  • 给区域赛成绩理想怀疑自己的大三女生回信

    千次阅读 多人点赞 2019-12-18 07:26:50
     很冒昧在这个时候给您发这封邮件,因为知道会不会打扰您的休息,希望不会吧。  我是一名在校大三的女生,专业偏计算机。我在大一的第二个学期进入了学校的程序设计实验室,开始了我的编程之路。到现在也就是...
  • 我上周听了由北京大学博古睿研究中心、中国人民大学哲学院、中国人民大学哲学与认知科学交叉平台、服务器艺术联合主办的“贞下起元:真实之虚幻 虚拟之现实”论坛,尤其是朱嘉明段永朝等老师的演讲,引起了我的思考...
  • 3爻是实践者而4等着3爻的连接,但是3爻的人不知道又跑到哪里尝试去了,会让4爻的人很苦恼。 4爻:关键词:保持敞开。4爻的人对世界有着深深的爱,4爻的人想要去拥抱大家拥抱这个世界,但是如果他们的信任被打破了...
  • 第四章 机交互技术概述 1.机交互的输入模式(第二版)  由于输入设备是多种多样的,而且对一个应用程序而言,可以有多个输入设备,同一个设备又可能为多个任务服务,这就要求对输入过程的处理要有合理的模式...
  • 你首先是一个,然后你才是程序员。

    万次阅读 多人点赞 2017-03-23 11:47:26
     这个层面,一直都是程序员的弱项,程序员被外界一直冠以“内向”、“爱说话”的美名,不是没有原因的。就LZ接触过的程序员,有不少确实是这种性格,这其实很利于未来的发展。  当然了,LZ也想说“应该多...
  • 接触型的卡片表面有金属贴片,用于连接卡内芯片和外界器具(洗衣机,电表,打水器)。而非接触性的卡片则是通过射频信号与器具进行信息传递。IC卡本身是无源的,需要依靠外部器具提供的能量驱动内部电路。时下更流行...
  • 同样的开场白,我竟然有了一点点陌生,或许是在同一个账号,或许是停了一段时间码字了,又或许是心态受到了很大的影响...不管怎么说,又大家见面了,见字如面,甚是想念,不错我就是五包辣条的那个辣条。 前言 ...
  • 四无年轻如何逆袭

    万次阅读 多人点赞 2017-04-26 06:53:25
    普普通通的年轻,没关系没资源,没有一技之长,没有什么兴趣爱好,该如何逆袭?
  • 网络成全视障学生追求美的天性 丰富多彩的外界环境是个体智力情绪等心理因素发展的必要 条件大脑的发育的成长成熟是建立在与外界环境广泛接触基础 之上的视觉是认识客观世界的重要途径之一也是维持个体正常 ...
  • LED怎么才能防水

    2020-10-22 00:49:39
    这里的外物含有工具,手指等均接触到灯具内的带电部分,以免触电受伤。IP防护等级是由两个数位所组成,数字越大表示它的防护等级越高。  第一个标示数字定义:  0、没有防护:对外界或物无特殊防护  1、...
  • 人类借助感觉器官从外界获取信息,而机器则借助传感器来研究自然现象规律及生产生活。...按测量方式可分为接触接触式两大类,按照传感器材料及电子元件特性分为热电阻热电偶两类。  温度传感器是最早开发
  • 良好的、合理的应用架构可以支持企业高效开展业务,控制经营风险,而混乱的、合理的应用架构则会限制企业的快速发展,成为企业增长与变革的瓶颈。 企业信息化建设已经发展了几十年,传统企业成熟互联网企业的...
  • 我的造论坛重开。目前除网址变更为www.zhangrex.com外,其它版面内容均未变,仍与十年前一样,也就是说,恭喜你穿越时光,来到了十年前的“造论坛”。当然,大多数链接,包括"造论坛"留言板都已失效,待以后...
  • 真正的智慧,源自于独立思考,真正有智慧的,有一套圆融的信念系统对事情本质的洞见。 下面要你分享的这12句话,蕴含着深深的智慧,因为他们源自NLP神经语言学家对上个世纪中期出现的几位大师的思想的总结...
  • 要本文首先从简化蹦床系统的模型开始通过人接触弹簧压至最低 端并通过蹬伸给系统能量 及弹簧从低端将弹起两个过程深入研究 从而计算出蹦床的运动机理并探究其安全性给出相应建议 在模型一中将蹦床简化为弹簧与...
  • 视觉系统:人类最重要的感觉

    千次阅读 2020-04-03 19:07:39
    总目录(持续更新中)(零)前言(一)视觉系统的全貌(二)光线如何被眼睛检测到?...近期打算小伙伴一起,创作一个专栏,专门讲解人类最重要的感觉系统:视觉系统。 本人在视觉神经科学的科研一线...
  • 很高兴铁汁能点开这篇博文,如果你能读完这篇文章,我由衷的感谢你,请放心,笔者不会浪费铁汁宝贵的时间,如果你现在正读大一、或者大二,亦或是你现在比较迷茫,知道如何系统的去学习,那么本篇文章后面的内容...
  • 台式机usb接口不好怎么办

    千次阅读 2021-07-01 00:51:35
    相关阅读: 接口简介 接口泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被修改内部而影响外界其他实体与其交互的方式。 人类与电脑等信息机器或人类与程序...
  • 电脑插上网线后设置上网的方法步骤当电脑接入网线后无法正常上网时,我们需要进入“网络共享中心”界面,查看并启用所有“被禁用”的本地连接。右击被禁用的连接,从其右键菜单中选择“启用”项即可。2...电脑与...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,142
精华内容 10,456
热门标签
关键字:

不和外界接触的人