首页 文章 精选 留言 我的

精选列表

搜索[教程],共9643篇文章
优秀的个人博客,低调大师

Javac 源码调试教程

为什么写这这篇文章 一直有读者问我 javac 源码怎么调试,自己也在写 JVM 掘金小册的过程中阅读了大量的 javac 的源码,网上这方面的文章也比较少,那就来写一篇 javac 源码调试的文章吧,作为 javac 系列文章的开篇。 javac 源码调试的过程是比较简单的,它本身就是一个用 Java 语言写的,对我们理解内部逻辑比较友好。 环境搭建过程 环境备注:Intellij、JDK8 1、第一步下载导入 javac 的源码 如果不想从 openjdk 下载折腾,可以跳过第 1 步直接从我的 github 下载:github.com/arthur-zhan… OpenJDK 的下载方式为: 打开hg.openjdk.java.net/jdk8/jdk8/l… ,点击左侧的 zip 或者 gz 进行下载。 在 Intellij 中新建一个 javac-source-code-reading 项目,把源码目录的 src/share/classes/com 目录整个拷贝到项目 src 目录下,删掉没用的 javadoc 目录。 2、找到 javac 主函数入口 代码在src/com/sun/tools/javac/Main.java 运行这个 main 函数,因为没有加需要编译的源代码路径,不出意外应该会在控制台会输出下面的内容 新建一个HelloWorld.java文件,内容随缘,在启动配置的Program arguments里加入 HelloWorld.java 的绝对路径。 再次运行 Main.java,会在 HelloWorld.java 的同级目录生成 HelloWorld.class 文件。 3、加断点 在 Main.java 中打上断点,开始调试以后会发现不管怎么设置,调试都会进入tool.jar,没有走刚刚导入的源码。 Intellij 中显示的是反编译 tools.jar 得到的源码,可读性没有源码那么好。 打开 Project Structure 页面(File->Project Structure), 选中图中 Dependencies 选项卡,把 <Moudle source> 顺序调整到项目 JDK 的上面: 再次调试就已经可以进入到项目源码中的断点处了。 javac 看字节码案例一:tableswitch 和 lookupswitch 选择的策略 读者提问,下面的代码编译出的 switch-case 语句为什么采用了 lookupswitch,而不是 tableswitch,不是说「如果 case 的值比较紧凑,中间有少量断层或者没有断层,会采用 tableswitch 来实现 switch-case」吗? public static void foo() { int a = 0; switch (a) { case 0: System.out.println("#0"); break; case 1: System.out.println("#1"); break; default: System.out.println("default"); break; } } 复制代码 对应字节码 public static void foo(); 0: iconst_0 1: istore_0 2: iload_0 3: lookupswitch { // 2 0: 28 1: 39 default: 50 } 复制代码 这个问题比较有意思,主要是 tableswitch 和 lookupswitch 代价的估算,代码在src/com/sun/tools/javac/jvm/Gen.java 中 在 case 值只有 0 和 1 两个值的情况下 hi=1 lo=0 nlabels = 2 // table_space_cost = 4 + (1 - 0 + 1) = 6 long table_space_cost = 4 + ((long) hi - lo + 1); // words // table_time_cost = 3 long table_time_cost = 3; // comparisons // lookup_space_cost = 3 + 2 * 2 = 7 long lookup_space_cost = 3 + 2 * (long) nlabels; // lookup_time_cost = 2 long lookup_time_cost = nlabels; // table_space_cost + 3 * table_time_cost = 6 + 3 * 3 = 15 // lookup_space_cost + 3 * lookup_time_cost = 7 + 3 * 2 = 13 // opcode = 15 <= 13 ? tableswitch : lookupswich int opcode = nlabels > 0 && table_space_cost + 3 * table_time_cost <= lookup_space_cost + 3 * lookup_time_cost ? tableswitch : lookupswitch; 复制代码 所以在 case 值只有 0, 1 两个的情况下,代价的计算是 table_space_cost + 3 * table_time_cost > lookup_space_cost + 3 * lookup_time_cost,lookupswich代价更小选 lookupswich 如果有 0, 1,2 三个呢? hi=2 lo=0 nlabels = 3 // table_space_cost = 4 + (2 - 0 + 1) = 7 long table_space_cost = 4 + ((long) hi - lo + 1); // words // table_time_cost = 3 long table_time_cost = 3; // comparisons // lookup_space_cost = 3 + 2 * 3 = 9 long lookup_space_cost = 3 + 2 * (long) nlabels; // lookup_time_cost = 3 long lookup_time_cost = nlabels; // table_space_cost + 3 * table_time_cost = 7 + 3 * 3 = 16 // lookup_space_cost + 3 * lookup_time_cost = 9 + 3 * 3 = 18 // opcode = 16 <= 18 ? tableswitch : lookupswich int opcode = nlabels > 0 && table_space_cost + 3 * table_time_cost <= lookup_space_cost + 3 * lookup_time_cost ? tableswitch : lookupswitch; 复制代码 所以在 case 值只有 0, 1,2 三个的情况下,代价的计算是 table_space_cost + 3 * table_time_cost < lookup_space_cost + 3 * lookup_time_cost,tableswitch 代价更小选 tableswitch 其实在数量极少的情况下,两个的差别不大,只是 javac 这里的算法导致选择了 lookupswitch javac 看字节码案例二:加载整数到栈上的字节码指令选择 我们知道有很多指令可以把整数加载到栈上,比如iconst_0、bipush、sipush、ldc,那它们是如何选择的呢? public static void foo() { int a = 0; int b = 6; int c = 130; int d = 33000; } 对应部分字节码 0: iconst_0 1: istore_0 2: bipush 6 4: istore_1 5: sipush 130 8: istore_2 9: ldc #2 // int 33000 11: istore_3 复制代码 在com/sun/tools/javac/jvm/Items.java 的 load() 函数加上断点 可以看到选择的策略依次往下: -1~5 之间选择 iconst_n 的方式 -128~127 之间选择 bipush -32768~32767 之间的选择 sipush 其它大整数选择 ldc 这与 java 虚拟机规范中字节码指令文档一致。 后记 用 javac 发掘很多有意思的东西,希望你能留言发现更好好玩的东东。 原文链接:https://juejin.cn/post/6844903882166894605 最后小编,还整理了一份面试宝典,有需要的添加小助理vx:mxzFAFAFA来领取!

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

GraphQL快速入门教程

摘要: 体验神奇的GraphQL! 原文:GraphQL 入门详解 作者:MudOnTire Fundebug经授权转载,版权归原作者所有。 GraphQL简介 定义 一种用于API调用的数据查询语言 核心思想 传统的api调用一般获取到的是后端组装好的一个完整对象,而前端可能只需要用其中的某些字段,大部分数据的查询和传输工作都浪费了。graphQL提供一种全新数据查询方式,可以只获取需要的数据,使api调用更灵活、高效和低成本。 特点 需要什么就获取什么数据 支持关系数据的查询 API无需定义各种路由,完全数据驱动 无需管理API版本,一个版本持续演进 支持大部分主流开发语言和平台 强大的配套开发工具 使用方法 下面我们通过搭建一个SpaceX的新闻网站来直观学习graphQL的基本使用方法,所有数据由 官方API 获得。 GraphQL服务端 服务端采用node + express。新建一个node项目,安装如下依赖: $ npm i graphql express-graphql express axios 创建入口文件 server.js,里面创建express服务。使用graphQL我们只需要设置一个路由,所有的请求都由这个graphQL的request handler处理: const express = require("express"); const graphqlHTTP = require("express-graphql"); const schema = require("./schema"); const app = express(); app.use( "/graphql", graphqlHTTP({ schema, graphiql: true }) ); const PORT = process.env.PORT || 5000; app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); graphqlHTTP是grapql的http服务,用于处理graphql的查询请求,它接收一个options参数,其中schema是一个 GraphQLSchema实例,我们接下来定义,graphiql设置为true可以在浏览器中直接对graphQL进行调试。更多express-graphql的用法请参考 Github express-graphql。 schema 接下来我们定义schema,schema意为‘模式’,其中定义了数据模型的结构、字段的类型、模型间的关系,是graphQL的核心。 新建schema.js文件,首先定义两个数据模型:LaunchType(发射)和 RocketType(火箭)。注意字段的数据类型需要使用GraphQL定义的,不能使用js中的基本数据类型。 const { GraphQLObjectType, GraphQLInt, GraphQLString, GraphQLBoolean, GraphQLList, GraphQLSchema } = require("graphql"); const LaunchType = new GraphQLObjectType({ name: "Launch", fields: () => ({ flight_number: { type: GraphQLInt }, mission_name: { type: GraphQLString }, launch_date_local: { type: GraphQLString }, launch_success: { type: GraphQLBoolean }, rocket: { type: RocketType } }) }); const LaunchType = new GraphQLObjectType({ name: "Rocket", fields: () => ({ rocket_id: { type: GraphQLString }, rocket_name: { type: GraphQLString }, rocket_type: { type: GraphQLString } }) }); 有了数据模型之后,我们需要从数据库或者第三方API获取数据,在此我们从spacex的官方API获取。我们需要定义一个root query,root query做为所有查询的入口,处理并返回数据,更多请参考 GraphQL Root fields & resolvers。 在 schema.js中增加代码: const axios = require("axios"); const RootQuery = new GraphQLObjectType({ name: "RootQueryType", fields: { launches: { type: new GraphQLList(LaunchType), resolve(parent, args) { return axios .get("https://api.spacexdata.com/v3/launches") .then(res => res.data); } } } }); module.exports = new GraphQLSchema({ query: RootQuery }); 查询列表 完成这一步,服务端api基本搭建完成!我们看一下效果,在浏览器中输入 http://localhost:5000/graphql 将打开 Graphiql(生产环境建议禁用): 我们可以只查询所有的 flight_number: 或者更多的属性: 是不是很简单很神奇! 单个查询 我们也可以通过传入参数查询单条信息: const RootQuery = new GraphQLObjectType({ name: "RootQueryType", fields: { launch: { type: LaunchType, args: { flight_number: { type: GraphQLInt } }, resolve(parent, args) { return axios .get( `https://api.spacexdata.com/v3/launches/${ args.flight_number }` ) .then(res => res.data); } } } }); 结果: 推荐大家使用Fundebug,一款很好用的BUG监控工具~ GraphQL前端 刚刚我们都是用GraphiQL在浏览器调用接口,接下来我们看一下在前端页面中怎么调用graphql服务。前端我们使用react。 在项目根目录初始化react项目: $ npx create-react-app client 为了便于调试,在package.json中增加scripts: "start": "node server.js", "server": "nodemon server.js", "client": "npm start --prefix client", "dev":"concurrently \"npm run server\" \"npm run client\" " 样式我们使用bootswatch中的一款主题: GraphQL的客户端有多种实现,本次项目使用 Apollo,最流行的GraphQL Client。更多client请参考 GraphQL Clients。 安装依赖 安装如下依赖: $ cd client $ npm i apollo-boost react-apollo graphql 其中 apollo-boost 是apollo client本身,react-apollo 是react视图层的集成,graphql 用于解析graphql的查询语句。 设置client 修改App.js内容如下: import React, { Component } from "react"; import ApolloClient from "apollo-boost"; import { ApolloProvider } from "react-apollo"; import "./theme.css"; import "./App.css"; import logo from "./spacex-logo-light.png"; const client = new ApolloClient({ uri: "http://localhost:5000/graphql" }); class App extends Component { render() { return ( <ApolloProvider client={client}> <div className="container"> <img src={logo} id="logo" /> </div> </ApolloProvider> ); } } export default App; 和redux使用<Provider>传递store类似,react-apollo 通过 <ApolloProvider>将apollo client向下传递。 实现query 接着我们来实现显示launches的component,新增文件 components/Launches.js: import React, { Component, Fragment } from "react"; import gql from "graphql-tag"; import { Query } from "react-apollo"; import LaunchItem from "./LaunchItem"; const LAUNCHES_QUERY = gql` query LaunchesQuery { launches { flight_number mission_name launch_date_local launch_success } } `; export class Launches extends Component { render() { return ( <Fragment> <h1 className="display-4 my-3">Launches</h1> <Query query={LAUNCHES_QUERY}> {({ loading, error, data }) => { if (loading) return <h4>Loading...</h4>; if (error) console.log(error); return ( <Fragment> {data.launches.map(launch => ( <LaunchItem key={launch.flight_number} launch={launch} /> ))} </Fragment> ); }} </Query> </Fragment> ); } } export default Launches; query语句通过 graphql-tag 定义,传入 <Query> 执行获取数据并传入 LaunchItem 显示。 components/LaunchItem.js: import React from "react"; export default function LaunchItem({ launch: { flight_number, mission_name, launch_date_local, launch_success } }) { return ( <div className="card card-body mb-3"> <div className="col-md-9"> <h4>Mission: {mission_name}</h4> <p>Date: {launch_date_local}</p> </div> <div className="col-md-3"> <button className="btn btn-secondary">Launch Details</button> </div> </div> ); } 查询语句通过graphql-tag定义,然后传入<Query>执行。 运行 由于本地调试,client和server分别运行在不同的端口,所以需要先进行跨域处理,使用 cors。 // server.js const cors = require('cors'); app.use(cors()); 效果 好了,大功告成,我们来看一下效果: 结语 今天就主要介绍GraphQL工程的搭建和GraphQL Query的使用,更多关于GraphQL的内容比如 Mutation下次有空会跟大家逐步讲解。 本文灵感来源:Youtube@Traversy Media,感谢 本文Demo Github地址:Github@MudOnTire 本文Demo线上展示:Heroku@graphql-spacex-launches 关于Fundebug Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用!

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

新手建站图文教程

目录 一、购买域名和空间二、虚拟空间配置三、上传网站源码四、域名绑定五、域名备案 一、购买域名和空间 1、什么是域名?域名(英语:Domain Name),简称域名、网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。-----这是百度百科上面的介绍通俗来说,你就理解成网址吧,就是访问你的网站的网址。 2、什么是虚拟空间可以理解成存放你源代码的网络硬盘,这个硬盘在哪你不用管,你往上放源码就好了。 3、这些在哪里买?推荐在阿里云购买,直接淘宝登陆授权一下就行,不用注册,多方便。阿里云优惠券地址域名购买地址 1)域名购买进入域名购买网页之后,搜索你自己想要的域名,如果没有被注册,恭喜你,你就可以直接购买了;如果已经被别人买了,那你只能换一个咯。 加入清单之后,结

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

教程: 使用PreparedStatement访问DLA

大家都知道PreparedStatement相比手动拼写SQL有很多好处,比如: 它会自动做敏感字符的转义,防止SQL Injection攻击。 它可以帮助我们动态执行SQL,Prepare一次之后,后续执行只需要替换参数就可以了。 它可以帮助以OOP的方式来写SQL相关相关代码,因为我们是通过 PrepareSteatement.setXxx()的方式而不是字符串拼接的方式来设置参数。 等等,PreparedStatement的好处还有很多,更多可以参考这篇《JDBC Statement vs PreparedStatement – SQL Injection Example》, 上面说的很详细。 今天我们Data Lake Analytics也引入了对PreparedStatement的支持, 今天给大家演示一下,如何用 Prepare

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

MPAndroidChart 教程:开始 Getting Started

入门 本章介绍使用此库的基本设置。 添加依赖 首先,将此库的依赖项添加到项目中。如何执行此操作在此存储库的用法部分中进行了描述。Gradle是使用此库作为依赖项的推荐方法。 创建视图 要使用LineChart, BarChart, ScatterChart, CandleStickChart, PieChart, BubbleChart or RadarChart,请在.xml中定义它: <com.github.mikephil.charting.charts.LineChart android:id="@+id/chart" android:layout_width="match_parent" android:layout_height="match_parent" /> 然后从您的Activity,Fragment或其他内容中检索它: // in this example, a LineChart is initialized from xml LineChart chart = (LineChart) findViewById(R.id.chart); 或者在代码中创建它(然后将其添加到布局中): // programmatically create a LineChart LineChart chart = new LineChart(Context); // get a layout defined in xml RelativeLayout rl = (RelativeLayout) findViewById(R.id.relativeLayout); rl.add(chart); // add the programmatically created chart 添加数据 拥有图表实例后,您可以创建数据并将其添加到图表中。此示例使用LineChart,其中Entry类表示图表中具有x和y坐标的单个条目。其他图表类型(例如BarChart)使用其他类(例如BarEntry)。 要将数据添加到图表中,请将您拥有的每个数据对象包装到Entry对象中,如下所示: YourData[] dataObjects = ...; List<Entry> entries = new ArrayList<Entry>(); for (YourData data : dataObjects) { // turn your data into Entry objects entries.add(new Entry(data.getValueX(), data.getValueY())); } 下一步,您需要将创建的List<Entry>添加到LineDataSet对象中。DataSet对象保存属于一起的数据,并允许对该数据进行单独设计。以下使用的“Label ”仅具有描述性目的,并在Legend中显示(如果已启用)。 LineDataSet dataSet = new LineDataSet(entries, "Label"); // add entries to dataset dataSet.setColor(...); dataSet.setValueTextColor(...); // styling, ... 最后一步,您需要将创建的LineDataSet对象(或多个对象)添加到LineData对象中。此对象包含由Chart实例表示的所有数据,并允许进一步样式化。创建数据对象后,您可以将其设置为图表并刷新它: LineData lineData = new LineData(dataSet); chart.setData(lineData); chart.invalidate(); // refresh 请考虑上面的场景一个非常基本的设置。有关更详细的说明,请参阅设置数据部分,它解释了如何根据示例将数据添加到各种图表类型。 造型 有关图表表面和数据的设置和样式的信息,请访问常规设置和样式部分。有关各个图表类型的更具体的样式和设置,请查看特定设置和样式Wiki页面。 参考: https://github.com/PhilJay/MPAndroidChart/wiki/Getting-Started https://blog.csdn.net/u014136472/article/details/50293767

资源下载

更多资源
Mario

Mario

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

Spring

Spring

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

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册