首页 文章 精选 留言 我的

精选列表

搜索[增删改查],共8589篇文章
优秀的个人博客,低调大师

【熵教育】Anders-SpringBoot中的Http应用:WebFlux——熵学院

我们今天开始进入Spring WebFlux.WebFlux是Spring5.0开始引入的.有别于SpringMVC的Servlet实现,它是完全支持异步和非阻塞的.在正式使用Spring WebFlux之前,我们首先得了解他和Servlet的区别,以及他们各自的优势,这样我们才能够给合适的场景选择合适的开发工具. 首先我们要问几个问题,为什么要有异步?在异步之前,软件行业做过哪些努力,他们的优势是什么?基于这几个问题,我们今天分享以下三个知识点: 从Http1.X 到Http2.0 从Servlet2.x到Servlet3.x WebFlux的出场 1. 从Http1.x到Http2.0 异步和同步是无法分开的.他们对性能的理解和处理也是各有千秋.传统的web项目因为是基于阻塞I/O模型而建立的,所以他们只能通过对整个链路的优化来提升性能,而这里的性能就包括了伸缩性和响应速度.这里面比较重要的一个环节就是网络传输.相对而言,这也是距离我们的用户最近的一个环节,因此他们对并发的处理以及对响应速度的处理就比其他的会更直接地影响我们的用户. 1.1 Http/1.x 在http1.x中,我们都知道,http会先进行三次握手,握手成功之后,开始传递数据,服务器响应完毕,就进行四次挥手,最后关闭链接.刚开始应用这个概念的时候,是非常受欢迎的,因为在那时候传递的还是静态页面或者动态数据比较少的资源,因此无论是客户端还是服务器端,他都节省了更多的资源.但随着互联网的飞速发展,这种方式就遇到了问题.如果每次传递数据都需要三次握手四次挥手的话,那么随着数据访问量的增加,那么三次握手四次挥手带来的资源消耗就会成为影响系统的瓶颈.这就好像一根针重量可以忽略,但当我们聚集上亿根针的时候,那么他的重量和所占用的空间,就成了必须要考虑的问题了. 那能不能建立好一次链接之后,我多传递几次数据,然后在关闭呢?当然可以,这就是长链接,也就是大家常说的"Keep-Alive".而HTTP1.1则是默认就开启了Keep-Alive.Keep-Alive虽然暂时性的解决了建立链接所带来的开销,也一定程度的提高了响应速度,但后来又凸显了另外两个问题: 首先,因为http是串行文件传输.所以当客户端请求a文件时,b文件只能等待.等待a链接到服务器,服务器处理文件,服务器返回文件这三个步骤完成后,b才能接着处理.我们假设,链接服务器,服务器处理,服务器返回各需要1秒,那么b处理完的时候就需要6秒,以此类推.(当然,这里有个前提,服务器和浏览器都是单通道的.)这就是我们说的阻塞. 其次,链接数的问题.我们都知道服务器的链接数是有限的.并且浏览器也对链接数有限制.这样能接入进来的服务就是有个数限制的,当达到这个限制的时候,其他的就需要等待链接被断开,然后新的请求才能够进入.这个比较容易理解. 之所以http1.x会使用串行文件传输,是因为http传输的无论是request还是response都是基于文本的,所以接收端无法知道数据的顺序,因此必须按着顺序传输.这也就限制了只要请求就必须新建立一个链接,这也就导致了第二个问题的出现. 1.2 Http/2 为了从根本上行解决http1.x所遗留的这两个问题,http2引入了二进制数据帧和流的概念.其中帧的作用就是对数据进行顺序标识,这样的话,接收端就可以根据顺序标识来进行数据合并了.同时,因为数据有了顺序,服务器和客户端就可以并行的传输数据,而这就是流所作的事情. 这样,因为服务器和客户端可以借助流进行并行的传递数据,那么同一台客户端就可以使用一个链接来进行传输,此时服务器能处理的并发数就有了质的飞跃. http/2的这个新特性,就是多路复用.我们可以看到,多路复用的本质就是并行传输.那web对请求的处理是否可以使用这个思路呢? 2.Servlet 现在我们来讨论Servlet与Netty.这两个一个主要是以同步阻塞的方式服务的,另一个是异步非阻塞的.这也就造成了他们适用的场景是不同的. 2.1 Servlet 做JavaWeb研发的几乎没有不知道Servlet的.在Servlet 3.0之前,Servlet采用Thread-Per-Request的方式处理请求,即每一次Http请求都由某一个线程从头到尾负责处理。如果一个请求需要进行IO操作,比如访问数据库、调用第三方服务接口等,那么其所对应的线程将同步地等待IO操作完成, 而IO操作是非常慢的,所以此时的线程并不能及时地释放回线程池以供后续使用,在并发量越来越大的情况下,这将带来严重的性能问题。为了解决这一的问题,Servlet3.0引入了异步处理. 在Servlet 3.0中,我们可以从HttpServletRequest对象中获得一个AsyncContext对象,该对象构成了异步处理的上下文,Request和Response对象都可从中获取。AsyncContext可以从当前线程传给另外的线程,并在新的线程中完成对请求的处理并返回结果给客户端,初始线程便可以还回给容器线程池以处理更多的请求。如此,通过将请求从一个线程传给另一个线程处理的过程便构成了Servlet 3.0中的异步处理。 这里举个例子,对于一个需要完成长时处理的Servlet来说,其实现通常为: packagetop.lianmengtu.testjson.servlet; importjavax.servlet.ServletException; importjavax.servlet.annotation.WebServlet; importjavax.servlet.http.HttpServlet; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.io.IOException; //@WebServlet("/syncHello"),因为使用的SpringBoot模拟,所以注释掉该注解 publicclassMyServletextendsHttpServlet{ @Override protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{ super.doGet(req,resp); newLongRunningProcess().run(); System.out.println("HelloWorld"); } } LongRunningProcess实现如下: packagetop.lianmengtu.testjson.servlet; importjava.util.concurrent.ThreadLocalRandom; publicclassLongRunningProcess{ publicvoidrun(){ try{ intmillis=ThreadLocalRandom.current().nextInt(2000); StringcurrentThread=Thread.currentThread().getName(); System.out.println(currentThread+"sleepfor"+millis+"milliseconds."); Thread.sleep(millis); }catch(InterruptedExceptione){ e.printStackTrace(); } } } 我们现在将MyServlet注入到Spring容器中: @Bean publicServletRegistrationBeanservletRegistrationBean(){ returnnewServletRegistrationBean(newMyServlet(),"/syncHello"); } 此时的SyncHelloServlet将顺序地先执行LongRunningProcess的run()方法,然后在控制台打印HelloWorld.而3.0则提供了对异步的支持,因此在Servlet3.0中我们可以这么写: @Override protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{ AsyncContextasyncContext=req.startAsync(); asyncContext.start(()->{ newLongRunningProcess().run(); try{ asyncContext.getResponse().getWriter().print("HelloWorld"); }catch(IOExceptione){ e.printStackTrace(); } asyncContext.complete(); }); } 此时,我们先通过request.startAsync()获取到该请求对应的AsyncContext,然后调用AsyncContext的start()方法进行异步处理,处理完毕后需要调用complete()方法告知Servlet容器。start()方法会向Servlet容器另外申请一个新的线程(可以是从Servlet容器中已有的主线程池获取,也可以另外维护一个线程池,不同容器实现可能不一样),然后在这个新的线程中继续处理请求,而原先的线程将被回收到主线程池中。事实上,这种方式对性能的改进不大,因为如果新的线程和初始线程共享同一个线程池的话,相当于闲置下了一个线程,但同时又占用了另一个线程。 Servlet 3.0对请求的处理虽然是异步的,但是对InputStream和OutputStream的IO操作却依然是阻塞的,对于数据量大的请求体或者返回体,阻塞IO也将导致不必要的等待。因此在Servlet 3.1中引入了非阻塞IO,通过在HttpServletRequest和HttpServletResponse中分别添加ReadListener和WriterListener方式,只有在IO数据满足一定条件时(比如数据准备好时),才进行后续的操作。 虽然Servlet3.1提供了异步的方式,并且做的也比Servlet3.0更彻底,但是如果我们使用了Servlet3.1提供的异步接口,像刚刚的代码演示的那样,那么我们在之后的处理中就没有办法再使用他原来的接口了.这就让我们处于了一种非此即彼的状况中.如果是这样,Servlet系列的技术,如SpringMVC也就是这样了.那怎么办呢? 3. WebFlux的出场 现在我们会从以下几个层面来探讨WebFlux 为什么要有WebFlux? Reactive定义与ReactiveAPI WebFlux中的性能问题 WebFlux的并发模型 WebFlux的适用性 3.1为什么要有WebFlux 首先,为什么要有webFlux? 在前面两部分,我们一直在探讨并发问题.为了解决并发,我们需要使用非阻塞的web技术栈.因为非阻塞的web栈使用的线程数更少,对硬件资源的要求更低.虽然Servlet3.1为非阻塞I/O提供了一些支持,但刚刚我们提到了,如果我们使用Servlet3.1里的非阻塞API,会导致我们无法再使用它原来的API.并且,自从非阻塞I/O以及异步概念出现之后,就诞生了一批专为异步和非阻塞I/O设计的服务器,比如Netty,这就催生了新的能服务于各种非阻塞I/O服务器的统一的API. WebFlux诞生的另一个重要原因是函数式程序设计.随着脚本型语言(Nodejs,Angular等)的扩张,函数式程序设计以及后继式API也相继火起来.以至于Java也在Java8中引入了Lambda来对函数式程序设计进行支持,又引入了StreamAPI来对后继式程序进行支持.由此,对具备函数式编程和后继式程序设计的Web框架的需求也越来越大了。 3.2Reactive的定义与API Reactive的定义 我们接触了"非阻塞"和"函数式",那reactive是什么意思呢? "reactive"这个术语指的是:围绕着对改变做出响应的程序设计模型---网络组件对IO事件做出响应,UIController对鼠标事件做出响应等等.在那种情况下,非阻塞取代了阻塞是响应式的,我们正处于响应模式中,当操作完成和数据变得可用的时候发起通知. 还有另一个重要的机制那就是我们在spring team里整合"reactive"以及非阻塞式背压机制.在同步里,命令式的代码,阻塞式地调用服务为普通的表单充当背压机制强迫调用者等待.在非阻塞式编程中,控制事件的频率就变得很重要防止快速的生产者不会压垮他的目的地. Reactive Streams 是一个定义了使用背压机制的异步组件之间交互设计的小型说明书(在Java9中也采纳了).例如,一个数据仓库(可以看做Publisher)可以生产数据,然后HTTP Server(看做订阅者)可以写入到响应里.Reactive Streams的主要目的是让订阅者可以控制生产者产生数据的速度有多快或有多慢. Reactive API Reactive Streams 在互操作性上扮演了一个很重要的角色.类库和基础设施组件虽然有趣,但对于应用程序API来说却用处甚少,因为他们太底层了.应用程序需要一个更高级别更丰富的函数式API来编写异步逻辑---和Java8里的StreamAPI很类似,不过不仅仅是为集合做准备的. Reactor 是为SpringWebFlux选择的一个reactive类库.它提供了Mono和Flux类型的API来处理0..1(Mono)和0..N(Flux)数据序列化通过一组丰富的操作集和ReactiveX vocabulary of operators对齐.Reactor 是一个Reactive Streams类库,所以他所有的操作都支持非阻塞背压机制.Reactor强烈地聚焦于Server端的Java.他在发展上和Spring有着紧密的协作. WebFlux要求Reactor作为一个核心依赖,但凭借Reactive Streams也可以和其他的reactive libraries一起使用.一般来说,一个WebFlux API 接收一个Publisher作为输入,转换给一个内置的Reactor类型来使用,最后返回一个Flux或一个Mono作为输出.所以,你可以批准任何的Publisher作为输入,你可以应用操作在输出上,但你因为你使用了其他的reactive library所以你需要进行转换.只要可行(例如,注解controllers),WebFlux可以在使用RXJava和另一个reactive library之间透明的改变.看Reactive Libraries获取更多地细节. 3.3 性能 性能这个词有很多特征和含义.Reactive 和非阻塞通常不会使应用程序运行地更快.在某些场景下,他们也可以.(例如,在并行条件下使用WebClient来执行远程调用的话).整体来说,非阻塞方式可能需要做更多的工作并且他也会稍微增加请求处理的时间. 对reactive和非阻塞好处的预期关键在于使用小,固定的线程数和更少的内存来扩展的能力.这使应用程序在加载的时候更加有弹性,因为他们以一种更可以预测的方式扩展.然而为了看到这些好处,你需要一些延迟(包括比较慢的不可预知的网络I/O).那是响应式堆栈开始显示他力量的地方,并且这些不同是非常吸引人的. 3.4并发模型 Spring MVC和Spring WebFlux都支持注解Controllers,但他们在并发模型和对阻塞和线程的默认呈现(assumptions)上是非常不同的.在Spring MVC(和通用的servlet应用)中,都假设应用程序是阻塞当前线程的(例如,远程调用),并且出于这个原因,servlet容器处理请求的期间使用一个巨大的线程池来吸收潜在的阻塞. 在Spring WebFlux(和非阻塞服务器)中,假设应用程序是非阻塞的,所以,非阻塞服务器使用小的,固定代销的线程池(event loop workders)来处理请求. "弹性伸缩"和"小数量的线程"或许听起来矛盾,但是对于不会阻塞当前线程(用依赖回调来取代)意味着你不需要额外的线程,因为非阻塞调用给处理了. 调用一个阻塞API 要是你需要使用阻塞库怎么办?Reactor和RxJava都提供了publishOn操作用一个不同的线程来继续处理.那意味着有一个简单的脱离舱口(一个可以离开非阻塞的出口).然而,请牢记,阻塞API对于并发模型来说不太合适. 易变的状态 在Reactor和RxJava里,你通过操作符生命逻辑,在运行时在不同的阶段里,都会形成一个进行数据序列化处理的管道.这样做的一个主要好处就是把应用程序从不同的状态保护中解放了出来,因为管道中的应用代码是绝不会被同时调用的. 线程模型 在运行了一个使用Spring WebFlux的服务器上,你期望看到什么线程呢? 在一个"vanilla"Spring WebFlux服务器上(例如,没有数据访问也没有其他可选的依赖),你能够看到一个服务器线程和几个其他的用来处理请求的线程(一般来说,线程的数目和CPU的核数是一样的).然而,Servlet容器在启动的时候就使用了更多的线程(例如,tomcat是10个),来支持servlet(阻塞)I/O和servlet3.1(非阻塞)I/O的用法. 响应式的WebClient操作是用Event Loop方式.所以你可以看到少量的固定数量的线程和他关联.(例如,使用了Reactor Netty连接的reactor-http-nio).然而,如果Reactor Netty在客户端和服务端都被使用了,这两者之间的event loop资源默认是被共享的. Reactor和RxJava提供了抽象化的线程池,调度器目的是结合publishOn操作符在不同的线程池之间切换操作.调度器有一个名字,建议这个名字是一个具体的并发策略--例如,"parallel"(因为CPU-bound使用有限的线程数来工作)或者"elastic"(因为I/O-bound使用大量的线程来工作).如果你看到这类的线程,这就意味着一些代码正在使用一个具体的使用了Scheduler策略的线程池. 数据访问库和其他第三方库依赖也创建和使用了他们自己的线程. 下次我们来分享Spring WebFlux的使用. 本文相关视频

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

android 35 ListView增删改

MainActivity package com.sxt.day05_11; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import com.sxt.day05_11.entity.GeneralBean; public class MainActivity extends Activity { ListView mlvGeneral; List<GeneralBean> mGenerals; GeneralAdapter mAdapter; private static final int ACTION_DETAILS=0; private static final int ACTION_ADD=1; private static final int ACTION_DELETE=2; private static final int ACTION_UPDATE=3; int mPosition; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initView(); setListener(); } private void setListener() { mlvGeneral.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) { AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this); builder.setTitle("选择以下操作") .setItems(new String[]{"查看详情","添加数据","删除数据","修改数据"}, new OnClickListener() {//倒的包是import android.content.DialogInterface.OnClickListener; @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case ACTION_DETAILS: showDetails(position);//这个position在mGenerals.get(position);调用,说明position是资源总条数范围, break; case ACTION_ADD: break; case ACTION_DELETE: mAdapter.remove(position);//调用适配器的删除方法 break; case ACTION_UPDATE: //启动修改的Activity,并将当前的军事家对象传递过去 Intent intent=new Intent(MainActivity.this, UpdateActivity.class); intent.putExtra("general", mGenerals.get(position));//mGenerals.get(position)的对象要实现序列化接口 mPosition=position; startActivityForResult(intent, ACTION_UPDATE);//要求返回结果,ACTION_UPDATE是requestCode break; } } private void showDetails(int position) { GeneralBean general=mGenerals.get(position); AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this); builder.setTitle(general.getName()) .setMessage(general.getDetails()) .setPositiveButton("返回", null);//直接关闭,没有响应事件 AlertDialog dialog = builder.create(); dialog.show(); } }); AlertDialog dialog = builder.create(); dialog.show(); return true; } }); } private void initView() { mlvGeneral=(ListView) findViewById(R.id.lvGeneral); mAdapter=new GeneralAdapter(mGenerals, this); mlvGeneral.setAdapter(mAdapter); } private void initData() { String[] names=getResources().getStringArray(R.array.general); String[] details=getResources().getStringArray(R.array.details); int[] resid={ R.drawable.baiqi,R.drawable.caocao,R.drawable.chengjisihan, R.drawable.hanxin,R.drawable.lishimin,R.drawable.nuerhachi, R.drawable.sunbin,R.drawable.sunwu,R.drawable.yuefei, R.drawable.zhuyuanzhang }; mGenerals=new ArrayList<GeneralBean>(); for (int i = 0; i < resid.length; i++) { GeneralBean general=new GeneralBean(resid[i], names[i], details[i]); mGenerals.add(general); } } class GeneralAdapter extends BaseAdapter{ List<GeneralBean> generals; MainActivity context; public void remove(int position){//适配器移出方法,就是移除资源总数据, generals.remove(position); notifyDataSetChanged();//BaseAdapter的方法,执行后安卓系统会调用getView()方法重新绘制, } public void add(GeneralBean general){ mGenerals.add(general); notifyDataSetChanged(); } public void update(int position,GeneralBean general){ mGenerals.set(position, general); notifyDataSetChanged(); } public GeneralAdapter(List<GeneralBean> generals, MainActivity context) { super(); this.generals = generals; this.context = context; } @Override public int getCount() { return generals.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder=null; if(convertView==null){ convertView=View.inflate(context, R.layout.item_general, null); holder=new ViewHolder(); holder.ivThumb=(ImageView) convertView.findViewById(R.id.ivThumb); holder.tvName=(TextView) convertView.findViewById(R.id.tvName); convertView.setTag(holder); }else{//滚屏的时候重复利用convertView holder=(ViewHolder) convertView.getTag(); } GeneralBean general=generals.get(position); holder.ivThumb.setImageResource(general.getResid()); holder.tvName.setText(general.getName()); return convertView; } class ViewHolder{ ImageView ivThumb; TextView tvName; } } @Override //处理UpdateActivity返回的结果 protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode!=RESULT_OK){//判断resultCode return ; } switch (requestCode) {//判断requestCode case ACTION_UPDATE: GeneralBean general=(GeneralBean) data.getSerializableExtra("general");//获取修改完以后的对象 mAdapter.update(mPosition, general);//调用适配器的更新方法,mPosition是修改的对象在集合的索引 break; case ACTION_ADD: break; } } } mainactivity页面: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/lvGeneral" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout> 修改Activity: package com.sxt.day05_11; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.ImageView; import com.sxt.day05_11.entity.GeneralBean; public class UpdateActivity extends Activity { //要修改对象的名字(控件显示),详细信息(控件显示), EditText metName,metDetails; ImageView mivThumb;//图片 int mPhotoId;//图片id @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_update); initView(); initData(); setListener(); } private void setListener() { setOKClickListtener(); setCancelClickListener(); } private void setCancelClickListener() { findViewById(R.id.btnCancel).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private void setOKClickListtener() { findViewById(R.id.btnOK).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String details=metDetails.getText().toString(); String name=metName.getText().toString(); //不能根据图片控件获取图片的id,所以多用一个变量保存图片的id GeneralBean general=new GeneralBean(mPhotoId, name, details); Intent intent=new Intent(UpdateActivity.this, MainActivity.class); intent.putExtra("general", general); setResult(RESULT_OK, intent);//RESULT_OK是resultCode结果码 finish();//关闭当前页面 } }); } //接收数据 private void initData() { Intent intent = getIntent(); GeneralBean general=(GeneralBean) intent.getSerializableExtra("general"); //数据显示在控件里面 metDetails.setText(general.getDetails()); metName.setText(general.getName()); mivThumb.setImageResource(general.getResid());//图片是根据id获取的 mPhotoId=general.getResid();//保存图片id } private void initView() { //用布局实例化对象 metDetails=(EditText) findViewById(R.id.etDetails); metName=(EditText) findViewById(R.id.etName); mivThumb=(ImageView) findViewById(R.id.iv_updae_thumb); } } 修改Activity页面: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/iv_updae_thumb" android:layout_width="80dp" android:layout_height="80dp" android:scaleType="fitXY" android:src="@drawable/baiqi"/> <EditText 可编辑的输入框 android:id="@+id/etName" android:layout_below="@id/iv_updae_thumb" android:layout_width="80dp" android:layout_height="wrap_content" android:text="白起"/> <EditText android:id="@+id/etDetails" android:layout_width="match_parent" android:layout_height="110dp" android:text="@string/detail" android:layout_toRightOf="@id/iv_updae_thumb"/> <Button android:id="@+id/btnOK" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="修改" android:layout_below="@id/etDetails" android:layout_marginLeft="50dp" android:layout_marginTop="20dp"/> <Button android:id="@+id/btnCancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="放弃" android:layout_below="@id/etDetails" android:layout_marginTop="20dp" android:layout_toRightOf="@id/btnOK" android:layout_marginLeft="50dp"/> </RelativeLayout> item_general.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > 横向 <ImageView android:id="@+id/ivThumb" android:layout_width="60dp" android:layout_height="60dp" android:scaleType="fitXY" 自动缩放 android:src="@drawable/baiqi"/> <TextView android:id="@+id/tvName" android:layout_width="wrap_content" android:layout_height="60dp" android:gravity="center_vertical" 内部垂直居中 android:textSize="20sp" android:text="白起" android:layout_marginLeft="10dp"/> </LinearLayout> 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/4889382.html,如需转载请自行联系原作者

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

hive 增删改 实例

pom <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-jdbc</artifactId> <version>0.11.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.2.0</version> </dependency> public class TeminalHiveCoreTest { public static void main(String[] args) throws SQLException { String tableName = " terminal "; String params ="appId,deviceMac,deviceId,deviceToken,deviceImsi,deviceModel,deviceManufacture,channel,appKey,userId,appVersion,versionCod,sdkType,sdkVersion,os,country,language,timezone,resolution,access,accessSubtype,carrier,cpu"; String partitionId ="appId"; String clusterId ="deviceToken"; String baseHdfsPath="hdfs://dev10.aoiplus.openpf:9000"; String hdfsPath=baseHdfsPath +"/user/hadoop/storm/terminalInfo_terminalInfo-3-0-1483076684221.log"; Connection connection = HiveJdbcConnection.getInstance().getConnection(HiveJdbcConnection.url, HiveJdbcConnection.user, HiveJdbcConnection.password); Statement stmt = connection.createStatement(); ResultSet res = null; HiveSqlDateDefineLanguage hqddl = new HiveSqlDateDefineLanguage().setCon(connection).setStmt(stmt); hqddl.dropTableByName(tableName); hqddl.createTableByParams(tableName, params,partitionId,clusterId); hqddl.loadSQL(tableName, hdfsPath); HiveSqlDateManageLanguage hqdml = new TermialHiveSqlDMLOperator().setCon(connection).setStmt(stmt).setRes(res); List<TerminalInfo> list = hqdml.findAll(tableName); System.out.println(list); HiveJdbcConnection.getInstance().close(res, stmt, connection); } } package com.curiousby.baoyou.cn.hive.base; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * @Type HiveJdbcConnection.java * @Desc * @author hadoop * @date 2016年12月29日 下午3:04:42 * @version */ public class HiveJdbcConnection { public static String driverName = "org.apache.hive.jdbc.HiveDriver"; public static String url ="jdbc:hive2://172.23.27.120:10000/default"; public static String user ="hive"; public static String password="hive"; static{ try { Class.forName(driverName); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new ExceptionInInitializerError(); } } private static HiveJdbcConnection instance = null; public static HiveJdbcConnection getInstance(){ if (instance == null ) { synchronized (HiveJdbcConnection.class) { if (instance == null ) { instance = new HiveJdbcConnection(); } } } return instance; } public Connection getConnection(String url,String user,String password) throws SQLException { return DriverManager.getConnection(url, user, password); } public void close(ResultSet rs, Statement st, Connection conn) { try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (st != null) st.close(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws SQLException { System.out.println(HiveJdbcConnection.getInstance().getConnection(url, user, password)); } } public class HiveSqlDateDefineLanguage implements SqlDateDefineLanguageInterface,SqlLoadData{ private Statement stmt; private ResultSet res; private Connection con; @Override public boolean createDatabase(String sql) { return false; } @Override public boolean createTable(String sql) { try { stmt.execute(sql); } catch (SQLException e) { e.printStackTrace(); return false; } return true; } /* CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] [COMMENT table_comment] [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path]*/ public boolean createTableByParams(String tableName,String params,String partitionedId,String clusteredId ){ String properties =""; String[] objects = params.split(","); for (int i = 0; i < objects.length; i++) { properties += objects[i] +" string,"; } properties = properties.substring(0, properties.length()-1); String sql =" create table " + tableName + " ("+ properties +") " +" comment '"+tableName+"' " // +" PARTITIONED BY ("+partitionedId+" string) " +" clustered by ("+clusteredId+") into 2 buckets " + " row format delimited fields terminated by ',' " // +" stored as orc " +" TBLPROPERTIES ('transactional'='true') " ; System.out.println(sql); return execute(sql); } @Override public boolean dropTable(String sql) { try { stmt.execute(sql); } catch (SQLException e) { e.printStackTrace(); return false; } return true; } public boolean dropTableByName(String tableName) { String sql ="drop table if exists " + tableName; return execute(sql); } public boolean execute(String sql) { try { stmt.execute(sql); } catch (SQLException e) { e.printStackTrace(); return false; } return true; } public Statement getStmt() { return stmt; } public ResultSet getRes() { return res; } public Connection getCon() { return con; } public HiveSqlDateDefineLanguage setStmt(Statement stmt) { this.stmt = stmt; return this; } public HiveSqlDateDefineLanguage setRes(ResultSet res) { this.res = res; return this; } public HiveSqlDateDefineLanguage setCon(Connection con) { this.con = con; return this; } @Override public boolean loadSQL(String tableName, String hdfsPath) { String sql = "LOAD DATA INPATH '"+hdfsPath+"' OVERWRITE INTO TABLE "+tableName; return execute(sql); } @Override public boolean loadLocalSQL(String tableName, String localPath) { String sql = "LOAD DATA local INPATH '"+localPath+"' OVERWRITE INTO TABLE "+tableName; return execute(sql); } } public abstract class HiveSqlDateManageLanguage extends SqlEntiyFormat<TerminalInfo> implements SqlDateManageLanguageInterface<TerminalInfo> { private Statement stmt; private ResultSet res; private Connection con; @Override public List<TerminalInfo> findAll(String tableName) { try { res = stmt.executeQuery("select * from " +tableName); List< TerminalInfo> list = formate(res); return list; } catch (SQLException e) { } return null; } @Override public TerminalInfo findOne(String key, String value) { return null; } @Override public TerminalInfo findOne(String sql) { return null; } @Override public List<TerminalInfo> findAllBySql(String sql) { return null; } @Override public boolean update(String sql) { return false; } @Override public boolean delete(String sql) { return false; } @Override public boolean insert(String sql) { return false; } @Override public boolean insert(TerminalInfo t) { return false; } public Statement getStmt() { return stmt; } public ResultSet getRes() { return res; } public Connection getCon() { return con; } public HiveSqlDateManageLanguage setStmt(Statement stmt) { this.stmt = stmt; return this; } public HiveSqlDateManageLanguage setRes(ResultSet res) { this.res = res; return this; } public HiveSqlDateManageLanguage setCon(Connection con) { this.con = con; return this; } } public class TermialHiveSqlDMLOperator extends HiveSqlDateManageLanguage{ @Override public void sqlMapper(ResultSet res, List<TerminalInfo> list) throws SQLException { TerminalInfo entity = new TerminalInfo(); entity .setAppId(res.getString(1)) .setDeviceMac(res.getString(2)) .setDeviceId(res.getString(3)) .setDeviceToken(res.getString(4)) .setDeviceImsi(res.getString(5)) .setDeviceModel(res.getString(6)) .setDeviceManufacture(res.getString(7)) .setChannel(res.getString(8)) .setAppKey(res.getString(9)) .setUserId(res.getString(10)) .setAppVersion(res.getString(1)) .setVersionCode(res.getString(12)) .setSdkType(res.getString(13)) .setSdkVersion(res.getString(14)) .setOs(res.getString(15)) .setCountry(res.getString(16)) .setLanguage(res.getString(17)) .setTimezone(res.getString(18)) .setResolution(res.getString(19)) .setAccess(res.getString(20)) .setAccessSubtype(res.getString(21)) .setCarrier(res.getString(22)) .setCpu(res.getString(23)) ; list.add(entity); } } public interface SqlLoadData { public boolean loadSQL(String tableName,String hdfsPath); public boolean loadLocalSQL(String tableName,String localPath); } public interface SqlMapper<T> { public void sqlMapper(ResultSet res , List< T> list) throws SQLException; } public abstract class SqlEntiyFormat<T> implements SqlMapper<T>{ public List<T> formate( ResultSet res) throws SQLException{ List< T> list = new ArrayList<T>(); while (res.next()) { sqlMapper(res, list); } return list; } } public interface SqlDateManageLanguageInterface<T> { public List<T> findAll(String tableName); public T findOne(String key ,String value); public T findOne (String sql); public List<T> findAllBySql (String sql); public boolean update (String sql); public boolean delete (String sql); public boolean insert(String sql); public boolean insert(T t); } /** * @Type SqlDateDefineLanguageInterface.java * @Desc CREATE DATABASE - 创建新数据库 ALTER DATABASE - 修改数据库 CREATE TABLE - 创建新表 ALTER TABLE - 变更(改变)数据库表 DROP TABLE - 删除表 CREATE INDEX - 创建索引(搜索键) DROP INDEX - 删除索引 * @author hadoop * @date 2016年12月29日 下午2:54:34 * @version */ public interface SqlDateDefineLanguageInterface { public boolean createDatabase(String sql); public boolean createTable(String sql); public boolean dropTable(String sql); public boolean dropTableByName(String tableName); } 捐助开发者 在兴趣的驱动下,写一个免费的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(右上角的爱心标志,支持支付宝和PayPal捐助),没钱捧个人场,谢谢各位。 谢谢您的赞助,我会做的更好!

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

【熵教育】Jacob-你所遗漏的SpringBoot日志管理知识——熵学院

Spring Boot对所有内部日志记录使用了Commons Logging,但是底层日志实现是开放的。可以为 Java Util日志、Log4J2和Logback。对于每种日志都预先配置为使用控制台输出和可选的文件输出。默认为Logback 日志配置 通过将相应的库添加到classpath可以激活各种日志系统,然后在classpath根目录下提供合适的配置文件可以进一步定制日志系统,配置文件也可以通过Spring Environment的logging.config属性指定。 以下文件会根据你选择的日志系统进行加载: 日志系统 定制配置 Logback logback-spring.xml,logback-spring.groovy,logback.xml或logback.groovy Log4j log4j.properties或log4j.xml Log4j2 log4j2-spring.xml或log4j2.xml JDK (Java Util Logging) logging.properties 注 如果可能的话,建议你使用-spring变种形式定义日志配置(例如,使用logback-spring.xml而不是logback.xml)。如果你使用标准的配置路径,Spring可能不能够完全控制日志初始化。 注 Java Util Logging从可执行jar运行时会导致一些已知的类加载问题,我们建议尽可能不使用它。 以下是从Spring Envrionment转换为System properties的一些有助于定制的配置属性: Spring Environment System Property Comments logging.exception-conversion-word LOG_EXCEPTION_CONVERSION_WORD 记录异常使用的关键字 logging.file LOG_FILE 如果指定就会在默认的日志配置中使用 logging.path LOG_PATH 如果指定就会在默认的日志配置中使用 logging.pattern.console CONSOLE_LOG_PATTERN 日志输出到控制台(stdout)时使用的模式(只支持默认的logback设置) logging.pattern.file FILE_LOG_PATTERN 日志输出到文件时使用的模式(如果LOG_FILE启用,只支持默认的logback设置) logging.pattern.level LOG_LEVEL_PATTERN 用来渲染日志级别的格式(默认%5p,只支持默认的logback设置) PID PID 当前的处理进程(process)ID(能够找到,且还没有用作OS环境变量) 所有支持的日志系统在解析配置文件时都能获取系统属性的值,具体可以参考spring-boot.jar中的默认配置。 log4j2配置 一份史诗级配置 /home/logs/log/dev \ \ \ \ </Appenders> <Loggers> <Root level="debug"> <AppenderRef ref="Console"/> <AppenderRef ref="debug"/> <AppenderRef ref="info"/> <AppenderRef ref="warn"/> <AppenderRef ref="error"/> </Root> </Loggers> 各个文件输出到不同级别的目录 设置最大保存时间为15天 每个文件最大50M tomcat的日志 在properties文件添加如下配置: server.tomcat.basedir=/home/logs/log-api/tomcat-logs server.tomcat.accesslog.enabled=true server.tomcat.accesslog.pattern=%t %a "%r" %s %D (%D ms) server.use-forward-headers=true lombok的神组合 使用lombok的@Slf4j 注解,省去配置声明log的繁琐,提高开发效率。 idea的 grep console组合 Grep Console 自定义设置控制台输出颜色,这样控制台就能比较明显的看到警告或者错误的信息,方便查找问题 视频:https://space.bilibili.com/313762729/#/

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

Android之Sqlite的增删操作

今天写了个sqlite CRUD的操作实例,这里做个笔记。android的存储方式有很多有sharedpreferenced、file、xml、sqlite等。 sqlite的介绍网络上实在是多,俺还是直接代码。对用户的注册情况进行CRUD操作。 1、首先创建个DBHelper继承SQLiteOpenHelper packagecom.xzw.db.utils; importandroid.content.Context; importandroid.database.sqlite.SQLiteDatabase; importandroid.database.sqlite.SQLiteDatabase.CursorFactory; importandroid.database.sqlite.SQLiteOpenHelper; /** *该类是一个数据库的帮助类,用于创建数据库 *@authorxzw * */ publicclassDBHelperextendsSQLiteOpenHelper{ privatestaticfinalStringTAG="DBHelper"; privateStringdbName; privateStringtableName; privateStringcreateTableSql; /** * *@paramcontext上下文 *@paramdbName数据库名 *@paramversion数据库版本号 *@paramtableName表名称 *@paramcreateTableSql建表Sql */ publicDBHelper(Contextcontext,StringdbName,intversion,StringtableName,StringcreateTableSql){ super(context,dbName,null,version); this.dbName=dbName; this.tableName=tableName; this.createTableSql=createTableSql; } @Override publicvoidonCreate(SQLiteDatabasedb){ db.execSQL(createTableSql); } @Override publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){ Stringsql="DROPTABLEIFEXISTS"+tableName; db.execSQL(sql); onCreate(db); } } 2、创建User对象 packagecom.xzw.db.bean; publicclassUser{ privateIntegeruserid; privateStringuserName; privateStringpassword; privateStringsex; privatelongregTime; publicUser(){ } publicUser(StringuserName,Stringpassword,Stringsex,longregTime){ this.userName=userName; this.password=password; this.sex=sex; this.regTime=regTime; } publicUser(Integeruserid,StringuserName,Stringpassword,Stringsex, longregTime){ this.userid=userid; this.userName=userName; this.password=password; this.sex=sex; this.regTime=regTime; } publicIntegergetUserid(){ returnuserid; } publicvoidsetUserid(Integeruserid){ this.userid=userid; } publicStringgetUserName(){ returnuserName; } publicvoidsetUserName(StringuserName){ this.userName=userName; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; } publicStringgetSex(){ returnsex; } publicvoidsetSex(Stringsex){ this.sex=sex; } publiclonggetRegTime(){ returnregTime; } publicvoidsetRegTime(longregTime){ this.regTime=regTime; } @Override publicStringtoString(){ //TODOAuto-generatedmethodstub return"[User]userid="+userid+",userName="+userName +",password="+password+",sex="+sex+",regTime=" +regTime; } } 3、创建UserStorage进行crud处理。 packagecom.xzw.db.utils; importjava.util.ArrayList; importjava.util.List; importcom.xzw.db.bean.User; importandroid.content.ContentValues; importandroid.content.Context; importandroid.database.Cursor; importandroid.database.sqlite.SQLiteDatabase; importandroid.util.Log; publicclassUserStorage{ privatestaticfinalStringTAG="UserStorage"; privatestaticfinalStringDB_NAME="user_data.db"; publicstaticfinalStringTABLE_NAME="user_data"; privatestaticfinalintDB_VERSION=1; staticfinalStringCOLUM_ID="_id"; staticfinalStringCOLUM_USER_NAME="username"; staticfinalStringCOLUM_PASSWORD="password"; staticfinalStringCOLUM_SEX="sex"; staticfinalStringCOLUM_REG_TIME="reg_time"; privateStringmCreateTableSql="createtableifnotexists"+TABLE_NAME +"("+COLUM_ID+"integerprimarykeyautoincrement," +COLUM_USER_NAME+"textnotnull," +COLUM_PASSWORD+"textnotnull," +COLUM_SEX+"text," +COLUM_REG_TIME+"bigintnotnull" +")"; privateDBHelperdbHelper; publicUserStorage(Contextcontext){ dbHelper=newDBHelper(context,DB_NAME,DB_VERSION,TABLE_NAME,mCreateTableSql); } /** *插入数据 *@paramcv *@return */ publiclonginsert(ContentValuescv){ //以写的方式创建或打开数据库 SQLiteDatabasedb=dbHelper.getWritableDatabase(); longresult=db.insert(TABLE_NAME,null,cv); db.close();//操作完成记得关闭数据库 if(result>0){ Log.i(TAG,"[Insert]success:"+result); }else{ Log.e(TAG,"Failedtoinsertinto"+TABLE_NAME); } returnresult; } /** *批量插入多条数据 *@paramcvs *@return */ publicintinsert(List<ContentValues>cvs){ intcount=0; SQLiteDatabasedb=dbHelper.getWritableDatabase(); for(ContentValuescv:cvs){ longid=insert(cv,db); count+=id>0?1:0; } db.close(); returncount; } /** *插入数据 *@paramcv *@paramdb *@return */ privatelonginsert(ContentValuescv,SQLiteDatabasedb){ longresult=db.insert(TABLE_NAME,null,cv); if(result>0){ Log.i(TAG,"[Insert]success:"+result); }else{ Log.e(TAG,"Failedtoinsertinto"+TABLE_NAME); } returnresult; } /** *根据id更新记录 *@paramcv *@paramid *@return */ publicintupdateUserById(ContentValuescv,Stringid){ SQLiteDatabasedb=dbHelper.getWritableDatabase(); intresult=db.update(TABLE_NAME,cv,"_id=?",newString[]{id}); db.close(); if(result>0){ Log.i(TAG,"[Update]success:"+result); }else{ Log.e(TAG,"Failedtoupate"+TABLE_NAME); } returnresult; } /** *获取所有列 *@return */ publicString[]getColumns(){ returnnewString[]{COLUM_ID,COLUM_USER_NAME,COLUM_PASSWORD,COLUM_SEX,COLUM_REG_TIME}; } publicList<User>getAllUser(){ List<User>users=newArrayList<User>(); SQLiteDatabasedb=dbHelper.getReadableDatabase(); Cursorcursor=db.query(TABLE_NAME,getColumns(),null,null,null,null,COLUM_ID); while(cursor.moveToNext()){ Useruser=fillUser(cursor); //添加user到集合中 users.add(user); } cursor.close();//游标使用完成后记得关闭 db.close(); returnusers; } privateUserfillUser(Cursorcursor){ Useruser=newUser(); user.setUserid(cursor.getInt(cursor.getColumnIndex(COLUM_ID))); user.setUserName(getValueByColumnName(cursor,COLUM_USER_NAME)); user.setPassword(getValueByColumnName(cursor,COLUM_PASSWORD)); user.setSex(getValueByColumnName(cursor,COLUM_SEX)); user.setRegTime(cursor.getLong(cursor.getColumnIndex(COLUM_REG_TIME))); returnuser; } /** *根据ID获取数据 *@paramid *@return */ publicUsergetUserById(Stringid){ SQLiteDatabasedb=dbHelper.getReadableDatabase(); Stringwhere="_id=?"; String[]selectionArgs=newString[]{id}; Cursorcursor=db.query(TABLE_NAME,getColumns(),where,selectionArgs,null,null,null); Useruser=null; if(cursor.moveToFirst()){ user=fillUser(cursor); } cursor.close();//游标使用完成后记得关闭 db.close(); returnuser; } /** *根据id删除记录 *@paramid *@return */ publicintdeleteById(Stringid){ SQLiteDatabasedb=dbHelper.getWritableDatabase(); intresult=db.delete(TABLE_NAME,"_id=?",newString[]{id}); db.close(); if(result>0){ Log.i(TAG,"[Delete]success:"+result); }else{ Log.e(TAG,"Failedtodeletefrom"+TABLE_NAME); } returnresult; } //获取字段值 privateStringgetValueByColumnName(Cursorcursor,StringcolumnName){ returncursor.getString(cursor.getColumnIndex(columnName)); } /** *清空表数据 *@paramid *@return */ publicvoidclear(){ SQLiteDatabasedb=dbHelper.getWritableDatabase(); db.delete(TABLE_NAME,null,null); db.close(); } } 4、编写UserService进行业务处理。 packagecom.xzw.db.utils; importjava.util.ArrayList; importjava.util.List; importandroid.content.ContentValues; importandroid.content.Context; importandroid.os.storage.StorageManager; importcom.xzw.db.bean.User; publicclassUserService{ privateUserStorageuserStorage; publicUserService(Contextcontext){ userStorage=newUserStorage(context); } /** *保存用户 * *@paramuser *@return */ publiclongsaveUser(Useruser){ ContentValuescv=fillContentValues(user); longcount=userStorage.insert(cv); returncount; } /** *批量保存用户 *@paramusers *@return */ publiclongsaveUser(List<User>users){ List<ContentValues>contentValues=newArrayList<ContentValues>(); for(Useruser:users){ ContentValuescv=fillContentValues(user); contentValues.add(cv); } longcount=userStorage.insert(contentValues); returncount; } /** *根据id修改数据 *@paramuser *@return */ publicintupdateUserById(Useruser){ ContentValuescontentValues=fillContentValues(user); returnuserStorage.updateUserById(contentValues,user.getUserid().toString()); } /** *获取所有用户信息 *@return */ publicList<User>getAllUser(){ returnuserStorage.getAllUser(); } /** *根据id获取用户信息 *@paramid *@return */ publicUsergetUserById(Stringid){ returnuserStorage.getUserById(id); } /** *根据id删除数据 *@paramid *@return */ publicintdeleteById(Stringid){ returnuserStorage.deleteById(id); } /** *删除所有数据 */ publicvoiddeleteAll(){ userStorage.clear(); } /** *填充数据 *@paramuser *@return */ privateContentValuesfillContentValues(Useruser){ //以下代码比较多地方会用带,故将其抽象成为方法。也是一种优化手段 ContentValuescv=newContentValues(); cv.put(UserStorage.COLUM_USER_NAME,user.getUserName()); cv.put(UserStorage.COLUM_PASSWORD,user.getPassword()); cv.put(UserStorage.COLUM_SEX,user.getSex()); cv.put(UserStorage.COLUM_REG_TIME,user.getRegTime()); returncv; } } 以上是整个业务流程了。现在使用AndroidTestCase进行测试 创建TestUser继承AndroidTestCase packagecom.xzw.db; importjava.util.ArrayList; importjava.util.List; importcom.xzw.db.bean.User; importcom.xzw.db.utils.UserService; importcom.xzw.db.utils.UserStorage; importandroid.test.AndroidTestCase; importandroid.util.Log; publicclassTestUserextendsAndroidTestCase{ privatestaticfinalStringTAG="TestUser"; /** *测试添加用户 */ publicvoidtestSave(){ UserServiceuserService=newUserService(this.getContext()); Useruser=newUser("xzw","123456","男",System.currentTimeMillis()); userService.saveUser(user); } /** *测试批量添加用户 */ publicvoidtestBatchSave(){ UserServiceuserService=newUserService(this.getContext()); List<User>users=newArrayList<User>(); for(inti=0;i<10;i++){ Useruser=newUser("hh-"+i,"123456",(i%2==0)?"男":"女",System.currentTimeMillis()); users.add(user); } userService.saveUser(users); } publicvoidtestGetAllUser(){ UserServiceuserService=newUserService(this.getContext()); List<User>users=userService.getAllUser(); for(Useruser:users){ Log.i(TAG,user.toString()); } } publicvoidtestGetUserById(){ UserServiceuserService=newUserService(this.getContext()); Useruser=userService.getUserById("2"); Log.i(TAG,user.toString()); } publicvoidtestUpdateUser(){ UserServiceuserService=newUserService(this.getContext()); Useruser=userService.getUserById("2"); user.setUserName("测试用户"); userService.updateUserById(user); } publicvoidtestDeleteById(){ UserServiceuserService=newUserService(this.getContext()); userService.deleteById("1"); } } 代码全部编写完毕,运行前需要在AndroidManifest.xml文件添加 <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.xzw.db" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <!--添加测试--> <uses-libraryandroid:name="android.test.runner"/> <activity android:name=".MainActivity" android:label="@string/title_activity_main"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> <!--添加测试目标包--> <instrumentationandroid:name="android.test.InstrumentationTestRunner" android:targetPackage="com.xzw.db"android:label="TestsforMyApp"/> </manifest> 以上就是整个sqlite crud的操作了。 查询所有用户信息: 根据id进行查询。 update后查询的结果。 以上就是完整的过程了。 本文转自xuzw13 51CTO博客,原文链接:http://blog.51cto.com/xuzhiwei/1054965,如需转载请自行联系原作者

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

Go语言恶意软件暴20倍

根据以色列安全公司Intezer的最新报告《地鼠年:2020年恶意软件综述》,在过去的四年中,随着国家黑客和网络犯罪纷纷转向新的技术生态系统,用Go编程语言编写的新恶意软件激增了2000%。 报告显示,尽管Go语言(有时被称为Golang),大约在九年前就被首次用于恶意软件,但直到2019年它才在网络犯罪分子中流行。 从那时起,Go已成为一种越来越普遍的选择,主要是因为它可以在Windows、Linux和Mac操作系统上运行,并且对研究人员进行逆向工程提出了难度较大的挑战。 Intezer还称赞Go具有“非常易于使用的编写良好的网络堆栈”。 报告指出,去年俄罗斯支持的黑客使用Zebrocy恶意软件的变体攻击了东欧国家。俄罗斯黑客还使用Go语言开发了WellMess恶意软件,该恶意软件针对英国、加拿大和美国的新冠疫苗研究人员。 在网络犯罪方面,Go语言编写的恶意软件包括用于发动DDoS攻击和非法开采加密货币的僵尸网络(IPStorm),以及全部用Go语言编写的勒索软件变体(Nefilim、EKANS)。 Intezer总结说,用户将需要专门的运行保护工具来应对Go恶意软件不断增长的威胁。 “我们看到攻击者针对操作系统的恶意软件来自同一Go代码库。由于许多因素,传统的防病毒程序很难识别Go恶意软件。基于代码重用的检测方法已证明是有效的,特别是在检测恶意软件家族方面。随着更多有价值的资产转移到云中,Go恶意软件对云环境的攻击也可能会增加。” 【本文是51CTO专栏作者“安全牛”的原创文章,转载请通过安全牛(微信公众号id:gooann-sectv)获取授权】 戳这里,看该作者更多好文

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

问题这样,拒做背锅侠

技术的锅太多,到底该不该你背? 话说这天一大早,那个悲催的中年架构师大刘又被手机微信群给炸醒。部门的运维兄弟在公司微信群里说: 短信的生产环境服务器 CPU 占用率过高,疯狂报警。是不是你们昨天上线看门狗导致的? 大刘迷了巴登的想了想,没错,昨天确实给短信服务装上了看门狗。但是看门狗服务肯定不会有问题(架构师必备的蜜汁自信),而且上线之前各轮测试也都测过了,没见过这个想象啊。 难道是测试妹子没测试到位?难道线上短信应用自身出现了问题? 生产无小事,小事更不能忽视,主要是怕扣绩效奖金。大刘迅速打开电脑,打开 VPN ,远程登上短信生产服务器,开始大刘最拿手的 2W1H 三板斧诊断之旅。 接下来的诊断内容有点烧脑,节奏有点快,请大家坐稳扶好。 1. 病号是谁(WHO)? 大刘拿出控制台诊断仪器,输入 top 命令一探究竟。我勒个去,不看不知道一看吓一跳,PID 为 1878 的病号,CPU 占用居然 200% 多。 问题算是定位到了,但是 PID 为 1878 的病号到底是谁,难道真是昨天上线的看门狗 ? 虽然大刘久经职场,但是排查生产问题时,内心还是比较忐忑,毕竟这是生产环境。 说时迟那时快,只见大刘一个命令输入: ps -ef | grep 1878 定睛一看,原来是放屁瞅别人,短信服务自己在作祟,和看门狗没关系,大刘心里一下子平缓了不少。 锅找到了主儿,其实这个时候大刘完全可以把这个问题甩给短信开发团队,但是大刘最喜欢做的不是甩锅,而是打破砂锅刨到底。 2. 病号哪里出了问题(WHERE)? 为什么 1878 号病人占用 CPU 会这么高呢? 只见黑乎乎的控制台诊断仪器上,大刘熟练的输入: jstack -l 1878 >> 1878号病历.log 这样便得到一份 1878 号病人的病历详情单,一会儿用得上。 到底 1878 号病人的哪个部位出了问题呢? 话没说完,只见大刘又在控制台诊断仪器上,输入一个: top -Hp 1878 白板黑字,把 1878 号病人的器官信息全部列了出来。 看到结果,甚是一惊,PID 代号为 8721 的器官占用 CPU 100% 多。 疑惑油然而生,这个 PID 代号 为 8721 的器官是啥,是头、是眼睛、还是胳膊腿呢?这些器官展示的 PID 列都是昵称,都这么善于伪装,如何揭露它的真面目呢? 还好大刘有高招,借助照妖镜算法,熟练的输入: printf "%x\n" 8721 果真使得代号为 8721 的器官,现了真身,真实身份居然是 2211 的呼吸道,怪不得病号一直气喘吁吁,上气不接下气。 到这一步还无法对症下药啊,还需要进一步确诊 2211 的呼吸道到底出了什么幺蛾子,导致 1878 号病人一直气喘吁吁,上气不接下气? 只见黑乎乎的控制台诊断仪器上,大刘再次飞一般的在输入: grep 2211 -A20 1878号病历.log 诊断结果随之显示在诊断仪器上。 曾经背了很多锅的大刘,看到诊断结果心里乐了一下,一眼就看出是高并发情况下用了 HashMap 的问题(请大家们自行寻找谷歌、百度,就不在此深入展开啦),终于拨开云雾见青天。 3. 如何对症下药( HOW )? 在大刘行云流水没有一丝一毫的拖泥带水般的神操作下,1878 号病人的诊断也就结束了,这个锅就彻底被打破了。 术业有专攻,大刘就可以郑重的告诉短信开发同事具体原因了,捉得病根,开发同事也就可以对症下药啦。 大刘这套行走江湖的诊断问题方式你 get 到了没?大刘自己简单概括为 2W1H 三板斧:病号是谁、病号哪里出了问题、对症下药。 1、病号是谁?(WHO) 第一步:采用 top 命令,找出 CPU 占用最高的病号 PID ; 第二步:通过 ps -ef | grep PID 查看病号对应的真实身份。 2、病号哪里出了问题?(WHERE) 第一步:采用 jstack -l PID >> PID.log 获取病号的各器官信息的病历单; 第二步:采用 top -Hp PID 拿到占用 CPU 最高的器官昵称 PID ; 第三步:采用 printf "%x\n" PID 根据器官昵称 PID 的拿到器官真实身份 TID ; 第四步:采用 grep TID -A20 pid.log 根据 TID 去病历单中匹配,确定是哪出了问题。 3、捉得病根、便可拿出医药箱,对症下药啦。(HOW) 作为程序猿,工作中难免会遇到不少类似这样的问题。面对问题,你如果像无头苍蝇一样乱撞,撞得头破血流依然不知道缘由,在背锅即将成为现实时,那就不妨试试大刘的 2W1H 三板斧的诊断方式,说不定会帮你快速定位、解决线上问题,毕竟快速的解决生产问题会把损失降到最低。 最后,想对大家说一句: 作为程序猿,一定要有程序猿的态度。避免背锅,拒绝甩锅,打破砂锅,从你我做起。 你好,我是四猿外,一家上市公司的技术总监,管理的技术团队一百余人。 我从一名非计算机专业的毕业生,转行到程序员,一路打拼,一路成长。 我会把自己的成长故事写成文章,把枯燥的技术文章写成故事。 欢迎关注我的公众号:四猿外

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

asp.net core 2.0 缺补漏

asp.net core 2.0 一些有用有趣的设置. 面向(targeting)不同的.net版本: 打开asp.net core 2.0的项目文件: xxx.csproj, 这部分: <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> </PropertyGroup> TargetFramework就是指向的版本. 也可以指向多个.net版本, 那就使用TargetFrameworks, 例如: <TargetFrameworks>netcoreapp2.0;net47</TargetFrameworks> 编译后, 在bin/debug文件夹下就会有两个文件夹: Microsoft.AspNetCore.All 并不是标准的Nuget包, 它不包含任何代码或dll, 它作为一个metapackage, 引用了很多其他的包而已 Program.cs asp.net core 应用其实就是一个控制台应用, 运行了asp.net core相关的库而已. program.cs里面都是对于宿主和环境的配置. 在这里, 已经进行了默认的配置. 但是如果你想捕获asp.net core启动时候的错误, 并显示错误页面, 那么: .CaptureStartupErrors(true) 是否应该监听Microsoft.AspNetCore.Hosting.Server.IServer制定的url(ipv4, v6, hostname, localhost, unix socket), 可以使用: .PreferHostingUrls(true) 监听指定的url: .UseUrls("http://0.0.0.0:5000") 使用ApplicationInsights: .UseApplicationInsights() Startup.cs startup里面是用来预加载/配置服务和中间件的. ConfigureServices方法用来注册服务. Configure方法用来配置请求管道. 添加mvc中间件, 就在ConfigureServices方法里: services.AddMvc(); 使用mvc中间件, 在Configure里: app.UseMvc(routes => { routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); }); Dependency Injection 每次调用创建一个实例: services.AddTransient<IEmailService, EmailService>(); 每次http请求创建一个实例: services.AddScoped<IEmailService, EmailService>(); 只创建一个实例: services.AddSingleton<IEmailService, EmailService>(); 如果你不想让容器自动dispose掉服务(容器会自动调用服务的Dispose方法), 那么你应该手动添加服务, 例如: services.AddSingleton(new EmailService()); http 请求管道中间件的顺序 最佳实践: 1. 异常处理中间件 2. 静态文件中间件 3. 用户验证中间件 4. mvc中间件 创建自定义中间件 有两种方法: 1. 直接在Startup里面写 可以使用四个方法: Run, Map, MapWhen, Use. Run方法直接短路, 返回Response. Map用于处理分支, 判断请求地址的开头, 为分支添加特定中间件等等 MapWhen也是处理分支, 但是可以控制分支的状态 Use, 可以调用下一个中间件(next.Invoke())或者短路请求. 2. 单独写一个类 public class CommunicationMiddleware { private readonly RequestDelegate _next; public CommunicationMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { await _next.Invoke(context); } } 然后再写一个extension 方法: public static class CommunicationMiddlewareExtension { public static IApplicationBuilder UseCommunicationMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<CommunicationMiddleware>(); } } 最后在Startup的Configure里调用即可: app.UseCommunicationMiddleware(); app.UseMvc(routes => { routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); }); Url Redirection 和 Url Rewriting 他们是不同的. url redirection是从服务器端绕了一圈, 然后回到客户端, 客户端收到301或者302之后, 再调用新地址. url rewriting是服务器端自己完成的, 客户端一无所知. 可以这样来使用Url Rewriting: var options = new RewriteOptions() .AddRewrite("NewUser", "/User/Registration/Index", false); app.UseRewriter(options); 异常处理 默认情况下400到599的错误信息都不会显示. 就会显示一个异常页面. 但是可以自定义错误页面: app.UseStatusCodePages("text/plain", "HTTP ERROR: Status Code: {0}"); 多个环境 asp.net core 2.0默认先加载appSettings.json, 然后根据环境不同再加载appSettings.{environment}.json. 如果有必要就覆盖或替换一些值. 根据环境使用不同的Startup文件: .UseStartup("AssemblyName") StartupDevelopment, StartupStaging, StartupProduction. Web Api的三种风格 RTC, 包含Action的Name Rest, 它是一种http协议的最佳实践方式而已. 主要目的是管理和控制资源. HATEOAS, 客户端通过遍历http response里面的超媒体链接, 可以动态导航到所需的资源, 酷. 使用HATEOAS, 需要安装包Halcyon.mvc下面是我的关于ASP.NET Core Web API相关技术的公众号--草根专栏:

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

C++缺补漏4,赶紧的

请说出const与#define 相比,有何优点? 答案:1)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。 2)有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel)答案:通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址*10H+通用寄存器内地址,就得到了真正要访问的地址。 当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)答案:肯定不是零。举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。 描述内存分配方式以及它们的区别?1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。 main 函数执行以前,还会执行什么代码?答案:全局对象的构造函数会在main 函数之前执行。 C++是不是类型安全的?答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。 有哪几种情况只能用intialization list 而不能用assignment? 答案:当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。 define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少? 答案:i 为30 New delete 与malloc free 的联系与区别?答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor. 1、写一个“标准”宏,这个宏输入两个参数并返回较小的一个。 .#define Min(X, Y) ((X)>(Y)?(Y):(X))//结尾没有; 2、嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。 while(1){}或者for(;;) 3、关键字static的作用是什么? 定义静态变量 4、关键字const有什么含意? 表示常量不可以修改的变量。 5、关键字volatile有什么含意?并举出三个不同的例子? 提示编译器对象的值可能在编译器未监测到的情况下改变。 int (*s[10])(int) 表示的是什么啊 int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。 1.有以下表达式: int a=248; b=4;int const c=21;const int *d=&a; int *const e=&b;int const *f const =&a; 请问下列表达式哪些会被编译器禁止?为什么? *c=32;d=&b;*d=43;e=34;e=&a;f=0x321f; *c 这是个什么东东,禁止 *d 说了是const, 禁止 e = &a 说了是const 禁止 const *f const =&a; 禁止 2.交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3; 有两种解法, 一种用算术算法, 一种用^(异或) a = a + b; b = a - b; a = a - b; or a = a^b;// 只能对int,char.. b = a^b; a = a^b; or a ^= b ^= a; 3.c和c++中的struct有什么不同? c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private 4.#i nclude <stdio.h> #i nclude <stdlib.h> void getmemory(char *p) { p=(char *) malloc(100); strcpy(p,"hello world"); } int main( ) { char *str=NULL; getmemory(str); printf("%s/n",str); free(str); return 0; } 程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险 5.char szstr[10]; strcpy(szstr,"0123456789"); 产生什么结果?为什么? 长度不一样,会造成非法的OS 6.列举几种进程的同步机制,并比较其优缺点。 原子操作 信号量机制 自旋锁 管程,会合,分布式系统 7.进程之间通信的途径 共享存储系统 消息传递系统 管道:以文件系统为基础 11.进程死锁的原因 资源竞争及进程推进顺序非法 12.死锁的4个必要条件 互斥、请求保持、不可剥夺、环路 13.死锁的处理 鸵鸟策略、预防策略、避免策略、检测与解除死锁 15. 操作系统中进程调度策略有哪几种? FCFS(先来先服务),优先级,时间片轮转,多级反馈 8.类的静态成员和非静态成员有何区别? 类的静态成员每个类只有一个,非静态成员每个对象一个 9.纯虚函数如何定义?使用时应注意什么? virtual void f()=0; 是接口,子类必须要实现 10.数组和链表的区别 数组:数据顺序存储,固定大小 连表:数据可以随机存储,大小可动态改变 12.ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点? 应用层 表示层 会话层 运输层 网络层 物理链路层 物理层 tcp /udp属于运输层 TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。 与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。 tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好 udp: 不提供稳定的服务,包头小,开销小 1:(void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针 .(void *)ptr 和 (*(void**))ptr值是相同的 2:int main() { int x=3; printf("%d",x); return 1; } 问函数既然不会被其它函数调用,为什么要返回1? mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息 1,要对绝对地址0x100000赋值,我们可以用 (unsigned int*)0x100000 = 1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做? *((void (*)( ))0x100000 ) ( ); 首先要将0x100000强制转换成函数指针,即: (void (*)())0x100000 然后再调用它: *((void (*)())0x100000)(); 用typedef可以看得更直观些: typedef void(*)() voidFuncPtr; *((voidFuncPtr)0x100000)(); 2,已知一个数组table,用一个宏定义,求出数据的元素个数 #define NTBL #define NTBL (sizeof(table)/sizeof(table[0])) 面试题: 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈? 进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。 每个线程有自己的堆栈。 DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈? 以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃 unsigned short A = 10; printf("~A = %u\n", ~A); char c=128; printf("c=%d\n",c); 输出多少?并分析过程 第一题,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285 第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。 这两道题都是在考察二进制向int或uint转换时的最高位处理。 分析下面的程序: void GetMemory(char **p,int num) { *p=(char *)malloc(num); } int main() { char *str=NULL; GetMemory(&str,100); strcpy(str,"hello"); free(str); if(str!=NULL) { strcpy(str,"world"); } printf("\n str is %s",str); getchar(); } 问输出结果是什么?希望大家能说说原因,先谢谢了 输出str is world。 free 只是释放的str指向的内存空间,它本身的值还是存在的. 所以free之后,有一个好的习惯就是将str=NULL. 此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的, 尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。 这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。 当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。 char a[10],strlen(a)为什么等于15?运行的结果 #i nclude "stdio.h" #i nclude "string.h" void main() { char aa[10]; printf("%d",strlen(aa)); } sizeof()和初不初始化,没有关系; strlen()和初始化有关。 char (*str)[20];/*str是一个数组指针,即指向数组的指针.*/ char *str[20];/*str是一个指针数组,其元素为指针型数据.*/ long a=0x801010; a+5=? 0x801010用二进制表示为:“1000 0000 0001 0000 0001 0000”,十进制的值为8392720,再加上5就是8392725罗 1)给定结构struct A { char t:4; char k:4; unsigned short i:8; unsigned long m; };问sizeof(A) = ? 给定结构struct A { char t:4; 4位 char k:4; 4位 unsigned short i:8; 8位 unsigned long m; // 偏移2字节保证4字节对齐 }; // 共8字节 2)下面的函数实现在一个数上加一个数,有什么错误?请改正。 int add_n ( int n ) { static int i = 100; i += n; return i; } 当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在 static上? // 帮忙分析一下 #i nclude<iostream.h> #i nclude <string.h> #i nclude <malloc.h> #i nclude <stdio.h> #i nclude <stdlib.h> #i nclude <memory.h> typedef struct AA { int b1:5; int b2:2; }AA; void main() { AA aa; char cc[100]; strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz"); memcpy(&aa,cc,sizeof(AA)); cout << aa.b1 <<endl; cout << aa.b2 <<endl; } 答案是 -16和1 首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit. 经过strcpy和memcpy后,aa的4个字节所存放的值是: 0,1,2,3的ASC码,即00110000,00110001,00110010,00110011 所以,最后一步:显示的是这4个字节的前5位,和之后的2位 分别为:10000,和01 因为int是有正负之分 所以:答案是-16和1 求函数返回值,输入x=9999; int func ( x ) { int countx = 0; while ( x ) { countx ++; x = x&(x-1); } return countx; } 结果呢? 知道了这是统计9999的二进制数值中有多少个1的函数,且有 9999=9×1024+512+256+15 9×1024中含有1的个数为2; 512中含有1的个数为1; 256中含有1的个数为1; 15中含有1的个数为4; 故共有1的个数为8,结果为8。 1000 - 1 = 0111,正好是原数取反。这就是原理。 用这种方法来求1的个数是很效率很高的。 不必去一个一个地移位。循环次数最少。 int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题 bool add (int a, int b,int *c) { *c=a+b; return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b))); } 分析: struct bit { int a:3; int b:2; int c:3; }; int main() { bit s; char *c=(char*)&s; cout<<sizeof(bit)<<endl; *c=0x99; cout << s.a <<endl <<s.b<<endl<<s.c<<endl; int a=-1; printf("%x",a); return 0; } 输出为什么是 4 1 -1 -4 ffffffff 因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100 当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理 b = -1; 当c为有符合数时, c = 100,即 c = 4,同理 b = 3 位域 : 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为: struct 位域结构名 { 位域列表 }; 其中位域列表的形式为: 类型说明符 位域名:位域长度 例如: struct bs { int a:8; int b:2; int c:6; }; 位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如: struct bs { int a:8; int b:2; int c:6; }data; 说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明: 1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如: struct bs { unsigned a:4 unsigned :0 /*空域*/ unsigned b:4 /*从下一单元开始存放*/ unsigned c:4 } 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。 2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。 3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如: struct k { int a:1 int :2 /*该2位不能使用*/ int b:3 int c:2 }; 从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。 二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 位域变量名•位域名 位域允许用各种格式输出。 main(){ struct bs { unsigned a:1; unsigned b:3; unsigned c:4; } bit,*pbit; bit.a=1; bit.b=7; bit.c=15; pri 改错: #i nclude <stdio.h> int main(void) { int **p; int arr[100]; p = &arr; return 0; } 解答: 搞错了,是指针类型不同, int **p; //二级指针 &arr; //得到的是指向第一维为100的数组的指针 #i nclude <stdio.h> int main(void) { int **p, *q; int arr[100]; q = arr; p = &q; return 0; } 下面这个程序执行后会有什么错误或者效果: #define MAX 255 int main() { unsigned char A[MAX],i;//i被定义为unsigned char for (i=0;i<=MAX;i++) A[i]=i; } 解答:死循环加数组越界访问(C/C++不进行数组越界检查) MAX=255 数组A的下标范围为:0..MAX-1,这是其一.. 其二.当i循环到255时,循环内执行: A[255]=255; 这句本身没有问题..但是返回for (i=0;i<=MAX;i++)语句时, 由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去. struct name1{ char str; short x; int num; } struct name2{ char str; int num; short x; } sizeof(struct name1)=8,sizeof(struct name2)=12 在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。 intel: A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)? static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。 他们都放在数据区,但是编译器对他们的命名是不同的。 如果要使变量在其他模块也有意义的话,需要使用extern关键字。 struct s1 { int i: 8; int j: 4; int a: 3; double b; }; struct s2 { int i: 8; int j: 4; double b; int a:3; }; printf("sizeof(s1)= %d\n", sizeof(s1)); printf("sizeof(s2)= %d\n", sizeof(s2)); result: 16, 24 第一个struct s1 { int i: 8; int j: 4; int a: 3; double b; }; 理论上是这样的,首先是i在相对0的位置,占8位一个字节,然后,j就在相对一个字节的位置,由于一个位置的字节数是4位的倍数,因此不用对齐,就放在那里了,然后是a,要在3位的倍数关系的位置上,因此要移一位,在15位的位置上放下,目前总共是18位,折算过来是2字节2位的样子,由于double是8字节的,因此要在相对0要是8个字节的位置上放下,因此从18位开始到8个字节之间的位置被忽略,直接放在8字节的位置了,因此,总共是16字节。 第二个最后会对照是不是结构体内最大数据的倍数,不是的话,会补成是最大数据的倍数 上面是基本问题,接下来是编程问题: 本人很弱,这几个题也搞不定,特来求救: 1)读文件file1.txt的内容(例如): 12 34 56 输出到file2.txt: 56 34 12 (逆序) 2)输出和为一个给定整数的所有组合 例如n=5 5=1+4;5=2+3(相加的数不能重复) 则输出 1,4;2,3。 望高手赐教!! 第一题,注意可增长数组的应用. #i nclude <stdio.h> #i nclude <stdlib.h> int main(void) { int MAX = 10; int *a = (int *)malloc(MAX * sizeof(int)); int *b; FILE *fp1; FILE *fp2; fp1 = fopen("a.txt","r"); if(fp1 == NULL) {printf("error1"); exit(-1); } fp2 = fopen("b.txt","w"); if(fp2 == NULL) {printf("error2"); exit(-1); } int i = 0; int j = 0; while(fscanf(fp1,"%d",&a[i]) != EOF) { i++; j++; if(i >= MAX) { MAX = 2 * MAX; b = (int*)realloc(a,MAX * sizeof(int)); if(b == NULL) { printf("error3"); exit(-1); } a = b; } } for(;--j >= 0;) fprintf(fp2,"%d\n",a[j]); fclose(fp1); fclose(fp2); return 0; } 第二题. #i nclude <stdio.h> int main(void) { unsigned long int i,j,k; printf("please input the number\n"); scanf("%d",&i); if( i % 2 == 0) j = i / 2; else j = i / 2 + 1; printf("The result is \n"); for(k = 0; k < j; k++) printf("%d = %d + %d\n",i,k,i - k); return 0; } #i nclude <stdio.h> void main() { unsigned long int a,i=1; scanf("%d",&a); if(a%2==0) { for(i=1;i<a/2;i++) printf("%d",a,a-i); } else for(i=1;i<=a/2;i++) printf(" %d, %d",i,a-i); } 兄弟,这样的题目若是做不出来实在是有些不应该, 给你一个递规反向输出字符串的例子,可谓是反序的经典例程. void inverse(char *p) { if( *p = = '\0' ) return; inverse( p+1 ); printf( "%c", *p ); } int main(int argc, char *argv[]) { inverse("abc\0"); return 0; } 借签了楼上的“递规反向输出” #i nclude <stdio.h> void test(FILE *fread, FILE *fwrite) { char buf[1024] = {0}; if (!fgets(buf, sizeof(buf), fread)) &nb ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2012/03/28/2422454.html,如需转载请自行联系原作者

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

C++缺补漏3,赶紧的

如何判断一段程序是由C 编译程序还是由C++编译程序编译的? 答案: #ifdef __cplusplus cout<<"c++"; #else cout<<"c"; #endif 如何打印出当前源文件的文件名以及源文件的当前行号? 答案: cout << __FILE__ ; cout<<__LINE__ ; __FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。 main 主函数执行完毕后,是否可能会再执行一段代码,给出说明? 答案:可以,可以用_onexit 注册一个函数,它会在main 之后执行。 #include <iostream> using namespace std; int fn1() { printf( "next.\n" ); return 0; } int fn2() { printf( "executed " ); return 0; } int fn3() { printf( "is " ); return 0; } int fn4() { printf( "This " ); return 0; } int _tmain(int argc, _TCHAR* argv[]) { _onexit( fn1 ); _onexit( fn2 ); _onexit( fn3 ); _onexit( fn4 ); printf( "This is executed first.\n" ); return 0; } 输出结果为: The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order.The functions passed to _onexit cannot take parameters. 类成员函数的重载、覆盖和隐藏区别? 答案: a.成员函数被重载的特征: (1)相同的范围(在同一个类中); (2)函数名字相同; (3)参数不同; (4)virtual 关键字可有可无。 (5)const的区别 b.覆盖是指派生类函数覆盖基类函数,特征是: (1)不同的范围(分别位于派生类与基类); (2)函数名字相同; (3)参数相同; (4)基类函数必须有virtual 关键字。 c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下: (1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。 (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2012/03/28/2422418.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

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

Spring

Spring

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

Rocky Linux

Rocky Linux

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

Sublime Text

Sublime Text

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

用户登录
用户注册