注意事项:
1.单向一对多
只需在“一”放进行配置
2.双向一对多
需要在关联双方都加以配置,而且需要在一的一方设置inverse=true
首先是实体类:
TAddress.java(多的一方)
public class TAddress implements Serializable {
private static final long serialVersionUID = 1121137857691229229L;
private Integer id;
private String address;
private String zipcode;
private String tel;
private String type;
private TUser user; //必须有
............
}
TUser.java(一的一方)
public class TUser implements Serializable {
private static final long serialVersionUID = 1224691192698621789L;
private Integer id;
private Integer age;
private String name;
@SuppressWarnings("rawtypes")
private Set address = new HashSet(); //多的一方放在集合中
....................
}
然后是各个实体类的配置文件
TAddress.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<!-- 一对多 -->
<hibernate-mapping>
<class name="com.model.TAddress" table="t_address"
dynamic-update="false" dynamic-insert="false">
<id name="id" type="java.lang.Integer" column="id" unsaved-value="0">
<generator class="native" />
</id>
<property name="address" column="address" type="string" />
<property name="tel" column="tel" type="string" />
<property name="zipcode" column="zipcode" type="string" />
<property name="type" column="type" type="string" />
<!-- 必须有many-to-one 否则关联字段(user_id)为null -->
<many-to-one name="user"
class="com.model.TUser"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="user_id"
not-null="true">
</many-to-one>
</class>
</hibernate-mapping>
TUser.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<!-- 一对多 外键关联 -->
<!-- Select from TUser where id=1 Select from TUser where id=1 to Select
from TUser where id=1 or id=2 -->
<!-- batch-size 批量加载机制 可以自定义每次批量加载的数量 -->
<hibernate-mapping>
<class name="com.model.TUser" table="t_user" dynamic-update="true"
>
<id name="id" type="java.lang.Integer" column="id" unsaved-value="0">
<generator class="native" />
</id>
<property name="name" column="name" />
<property name="age" column="age" />
<set name="address" table="t_address" cascade="all" order-by="zipcode asc"
lazy="true" inverse="true">
<key column="user_id" /><!-- 确定关联的外键列 -->
<one-to-many class="com.model.TAddress" />
</set>
</class>
</hibernate-mapping>
其次是hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- properties -->
<!-- 数据库URL -->
<property name="hibernate.connection.url">jdbc:mysql://localhost/onetomany</property>
<!-- 数据库JDBC驱动 -->
<property name="hibernate.connection.driver_class">org.gjt.mm.mysql.Driver</property>
<!-- 数据库用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库密码 -->
<property name="hibernate.connection.password">hello</property>
<!-- 数据库方言 -->
<property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
<!-- 是否日志调试 -->
<property name="show_sql">true</property>
<!-- 是否使用数据库外连接 -->
<property name="use_outer_join">true</property>
<!-- 事务管理 使用JDBC Transaction(使用JTA会报错) -->
<property name="transaction.factory_class">
net.sf.hibernate.transaction.JDBCTransactionFactory
</property>
<!-- 指定hibernate每次提交的SQL数量 对批量操作的性能提升帮助很大!!!!!!!!!!!!! -->
<property name="hibernate.jdbc.batch_size">25</property>
<!-- 映射文件配置,配置文件名必须包含其相对于根的全路径 -->
<mapping resource="com/model/TUser.hbm.xml" />
<mapping resource="com/model/TAddress.hbm.xml" />
</session-factory>
</hibernate-configuration>
测试代码(部分)
增加
public void testSave(){
try {
Transaction tx=session.beginTransaction();
// TUser user=(TUser) session.load(TUser.class, 1);
TUser user=new TUser();
user.setName("zhangsan");
user.setAge(20);
TAddress address=new TAddress();
address.setAddress("jingsan");
address.setTel("1361380");
address.setZipcode("45000");
address.setType("java");
address.setUser(user); //设置关联的TUser对象
user.getAddress().add(address);
session.save(user); //级联更新
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
}
}
查询
public void testLoad(){
try {
Transaction tx=session.beginTransaction();
String hql="from TUser where name='zhangsan'";
List list=session.createQuery(hql).list();
System.out.println("-------------1------------");
Iterator iter=list.iterator();
while(iter.hasNext()){
TUser user=(TUser) iter.next();
System.out.println("--------------2------------");
System.out.println("user.name="+user.getName());
System.out.println("--------------3------------");
System.out.println("user.address="+user.getAddress().size());
System.out.println("--------------4------------");
}
} catch (HibernateException e) {
e.printStackTrace();
}
}
批量插入(可以提高性能)
实现机制:如果使用了批量加载机制,hibernate在进行数据查询操作前,会自动在当前session中寻找是否还存在
其他同类型待加载的数据,如果有,则将其查询条件合并在当前的select语句中一并提交,这样,通过
一次数据库操作即完成了多个读取任务。
//批量插入操作性能优化 通过配置<property name="hibernate.jdbc.batch_size">25</property>
public void testBatchInsert(){
long start=System.currentTimeMillis();
this.importUserList();
long end=System.currentTimeMillis();
System.out.println("批量插入花费时间是"+(end-start));
}
public void importUserList(){
try {
Transaction tx=session.beginTransaction();
for(int i=0;i<10000;i++){
TUser user=new TUser();
user.setName("user"+i);
session.save(user);
if(i%25==0){ //以每25个数据作为一个处理单元
session.flush();
session.clear();
}
}
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
}
}
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- properties -->
<!-- 数据库URL -->
<property name="hibernate.connection.url">jdbc:mysql://localhost/tablepersubclass</property>
<!-- 数据库JDBC驱动 -->
<property name="hibernate.connection.driver_class">org.gjt.mm.mysql.Driver</property>
<!-- 数据库用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库密码 -->
<property name="hibernate.connection.password">hello</property>
<!-- 数据库方言 -->
<property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
<!-- 是否日志调试 -->
<property name="show_sql">true</property>
<!-- 是否使用数据库外连接 -->
<property name="use_outer_join">true</property>
<!-- 事务管理 使用JDBC Transaction(使用JTA会报错) -->
<property name="transaction.factory_class">
net.sf.hibernate.transaction.JDBCTransactionFactory
</property>
<!-- 映射文件配置,配置文件名必须包含其相对于根的全路径 -->
<mapping resource="com/model/TItem.hbm.xml" />
</session-factory>
</hibernate-configuration>
把日志调试设置为true,需要log4j.properties配置文件支持
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=warn, stdout
log4j.logger.net.sf.hibernate=info
### log just the SQL
#log4j.logger.net.sf.hibernate.SQL=debug
### log JDBC bind parameters 把这一行改为debug ###
log4j.logger.net.sf.hibernate.type=debug
### log schema export/update ###
log4j.logger.net.sf.hibernate.tool.hbm2ddl=debug
### log cache activity ###
#log4j.logger.net.sf.hibernate.cache=debug
### log jdbc resource acquisition
#log4j.logger.net.sf.hibernate.impl.BatcherImpl=debug
### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.net.sf.hibernate.connection.DriverManagerConnectionProvider=trace
一直想学Linux,在校期间有Linux选修课,看到教员在上课侃侃而谈、命令操纵随心而动……
最近项目忙完了,就开始着手学习。本人安装的Redhat AS4,相关安装步骤网上有很多,就不再详细介绍了。(如有需要再单独写一遍安装、初步使用等文章)
安装完成后输入账户进入系统就开始进行Linux命令学习。
创建用户:
useradd chenyang【用户名】 ---添加用户
passwd chenyang【用户名】 ---设置密码
注:新建用户"chenyang"在/home下面
用户之间切换用:su
清屏命令:clear
显示当前用户:whoami
userdel chenyang【用户名】 ---删除用户
userdel –rf chenyang【用户名】 ---删除用户所在的目录
创建组:
groupadd newgroup【组名】 ---添加组
注:新建组在/etc下面,用more group查看
groupdel newgroup 【组名】 ---删除组
安装JDK:
1.
先查看系统是否有默认的jdk rpm -qa|grep gcj
如果有可以选择卸载或继续使用 卸载:rpm –e 要卸载的jdk
2.
下载jdk for Linux,比如 jdk-6u25-linux-i586-rpm.bin
3.
上传到Linux系统中,使用SSH SecureShellClient,SSH SecureShellClient是非常好用的把window上的文件上传到Linux上的工具,我用的是从这http://download.csdn.net/source/3525638下载的,网友可以也可以从别的地方下载
4.
文件上传到Linux系统中后,需要改变文件权限,不然不能安装 chmod 777 jdk-6u25-linux-i586-rpm.bin
5.
./jdk-6u25-linux-i586-rpm.bin(中间不能有空格)
6.
安装jdk rpm -ivh jdk-6u25-linux-i586.rpm
安装成功后java目录在/usr下面
7.
配置环境变量
需要进入/etc目录下,然后vi profile
输入o就可以像在window下的记事本编辑
export JAVA_HOME=/usr/java/jdk1.6.0_25
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
(至于这样设置的原因,可以看这篇文章http://www.cnblogs.com/wangchenyang/archive/2011/08/17/2143620.html)
完成后按"Esc"键,然后输入:w就可以保存,退出时输入:q,可以简单些,直接输入:wq
输入:q!是直接退出不保存
8.测试
写个test.java文件(文件名不重要)
vi test.java
class test{
public static void main(String[] args){
System.out.println("hello linux");
}
}
javac test.java
java test
若显示hello linux,恭喜你!jdk正确安装,否则环境变量等有问题。
从大二开始接触Java,之后是断断续续的学习。大三真正开始Java之旅,估计大部分初学者在学Java时被Java的环境变量搞的晕头转向,虽然找到了正确设置环境变量的方式,但其中的原因一知半解,设置压根不知道是何原因。
今天为止对环境变量的设置还不是很懂,而且网上的大部分资料几乎都是设置方法,没有说原因。今天学Linux,遇到了Java环境变量的设置,无意间找到了详细透彻讲解Java环境变量的设置。
“
1. PATH环境变量。作用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序。我们需要把 jdk安装目录下的bin目录增加到现有的PATH变量中,bin目录中包含经常要用到的可执行文件如javac/java/javadoc等待,设置好 PATH变量后,就可以在任何目录下执行javac/java等工具了。
2. CLASSPATH环境变量。作用是指定类搜索路径,要使用已经编写好的类,前提当然是能够找到它们了,JVM就是通过CLASSPTH来寻找类的。我们 需要把jdk安装目录下的lib子目录中的dt.jar和tools.jar设置到CLASSPATH中,当然,当前目录“.”也必须加入到该变量中。
3. JAVA_HOME环境变量。它指向jdk的安装目录,Eclipse/NetBeans/Tomcat等软件就是通过搜索JAVA_HOME变量来找到并使用安装好的jdk。
”
在此要感谢“SamCN”,谢谢你的这边文章,不仅解决了Linux中遇到了问题,而且解决了学Java那么长时间的困惑。谢谢!
寻找出色的产品经理
“哪里能找到出色的产品经理?”CEO经常问我这个问题。
我总是这样回答:出色的产品经理就在公司里,只不过在其他岗位上,有可能是软件工程师、用户体验设计师、系统工程师,等着伯乐去发掘。无论你打算从公司内部还是从公司外部招聘产品经理,必须清楚合适的人选应该具备哪些特质。这一章,我将列举产品经理应有的特质。
个人素质和态度
技术可以学习,素质却难以培养,有些素质是成功的产品经理必不可少的。
~~对产品的热情
有这样一群人,他们对产品有一种本能的热爱,把自己生活中的一切事物都看成产品,怀揣对优秀的产品的热爱和尊重。这份热情是产品经理必备的素质,是他们夜以继日克服困难、完善产品的动力。这份热情能感染团队成员,激励所有人。
辨别这种特质很容易,可以让应聘者谈谈自己最喜欢的产品及喜欢的原因,聊聊不同领域的产品和他讨厌的产品,问问对方,如果有机会,他打算怎样完善自己最喜欢的产品。热情是难以伪装的,虚伪的做作容易毕露无遗。
~~用户立场
理想的产品经理不一定来自产品的目标市场(这种情况有利也有弊),但是他必须融入目标市场。这一特质对制造大众产品的高科技企业尤为难得。我们倾向于从自己的角度去理解用户和市场。事实上,目标用户的经验、喜好、价值观、知觉能力、忍受程度、技术理解很可能与我们的大相径庭。
可以就产品的目标市场向应聘者发问,让他谈谈如何换位思考。了解应聘者对目标市场的感觉,最重要的是看对方是尊重目标市场希望融入其中,还是打算一意孤行改变用户习惯。
对国际化的产品和针对特定地域的产品来说,换位思考尤其重要。各种文化虽有共通之处,但也存在许多差异。有些差异对产品无关紧要,有些则至关重要。应该考察应聘者是否足够了解目标市场,能否区分这两种差异。
~~智力
人的智力水平是无法替换的。产品管理需要洞察力和判断力,因此必须具备敏锐的头脑。勤奋当然是必需的,但从事这项工作光有勤奋还远远不够。
招聘聪明人是项知易行难的任务,结果在很大程度上取决于招聘者的能力和可靠性。常言道,“物以类聚,人以群分”,此言不虚。方法之一是测试应聘者解决问题的能力。微软令人称道的、深入而有效的面试,即是考察应聘者解决问题的能力,通常由一位或多位领域专家就一个问题对应聘者进行深入考察。面试官不关心应聘者是否知道正确答案,而看重应聘者解决问题的思路和方法(智力优于知识)。如果应聘者回答正确,面试官会将问题略作调整,询问应聘者在新情况下如何应付。重复这个过程,直到应聘者被迫处理他不知道答案的情况,说出解决方法。
~~职业操守
每种团队角色承担的义务和付出的努力都不相同。产品经理肩负着产品的前途和命运,绝不适合贪图安逸的人担任。即便掌握了时间管理和产品管理的技巧,产品经理依然要为产品投入大量精力。成功的产品经理能拥有时间享受清闲的家庭生活吗?只要具备足够的经验,我相信可以做到。但是,如果你期望的是一周只工作四十个小时,下班后把工作抛诸脑后,那是不现实的。
成功的产品经理需要付出多少努力?在这个问题上,我对应聘者向来坦率,产品管理工作绝不能用时间来衡量,付出多少都不为过。紧急情况下临时找来的“救火队员”多半不是合适的产品经理人选。
在漫长的项目周期里,产品经理需要付出的努力和承担的义务并非一成不变。有的阶段比较轻松,有的阶段则很紧张。但是称职的产品经理对产品的关注和忧虑程度,以及愿意为之付出努力的热情是不会改变的。
~~正直
在所有产品团队成员里,产品经理最能体现公司和产品的价值观。通常产品经理不直接管理团队成员,不能要求别人执行命令,所以他必须通过行动影响、说服身边的同事。这种影响基于相互的信任和尊重,要求产品经理必须是个正直的人。
产品经理是产品团队、销售团队、公司高管之间的枢纽,经常要协调处理各种问题,比如提早供货、满足大客户的特殊要求。产品经理如何处理这些难题,同事们都看在眼里。
信任和尊重需要时间培养,产品经理唯有通过工作展示自己的素质和能力,才能成为真正的团队领导。如果产品经理对待同事缺乏诚意,怀有私心,一碗水端不平,那么势必会影响整体团结和工作效率。产品经理虽然不必事事精通,但应当知道每位成员最擅长做什么,尊重大家发挥工作特长的意愿,充分信任大家。
考察一个人是否正直绝不比考察他的智力容易,考察陌生的应聘者是否正直就更难了。对那些有工作经验的应聘者,可以问问他们如何处理工作中的压力,多追问工作细节。
~~信心
很多人相信经验可以让人产生自信。如果仅凭经验可以建立信心,为什么许多工作多年的产品经理却毫无自信?相反,刚刚步入社会的大学毕业生却往往充满自信(虽然这种自信通常源自对自身状况的无知)。
自信是很重要的素质。公司高管、产品团队、销售团队都需要看到产品经理的信心,确信他们投入的时间、金钱、努力不会付之东流。自信的人更有说服力,更容易成为人们愿意追随的领导者。
~~态度
称职的产品经理把自己当成产品的CEO,愿意为产品的最终成败承担全部责任,绝不找借口。虽然他清楚产品按时成功上市要克服许多困难——开发难度大、开发时间长、成本过高、产品复杂等,但他明白预见和解决这些问题是他的责任。
这并不是说产品经理要事必恭亲,监督每个人的工作,而是指出现问题时他应该及时承担责任,进展顺利时他应该及时给大家以鼓励。称职的产品经理知道,虽然产品的实现离不开大家的协助,但是他应该对自己的产品创意负责。
技能
掌握一些重要的技能是打造成功产品的关键。我相信,只要具备优秀的个人素质,所有技能都可以习得。
~~运用技术的能力
很多成功的产品经理是工程师出身,因为策划产品在很大程度上取决于对新技术的理解,以及如何应用技术解决相关的问题。
出色的产品经理并不需要自己发明或实现新技术,但必须有能力理解技术、发掘技术的应用潜力。
培养理解技术的能力有多种途径,可以参加培训课程,阅读相关书籍和文章,向程序员和架构师请教,参加开发团队的头脑风暴也不失为一种途径。
~~注意力
产品经理要优先解决重要问题。研发产品的过程中有很多干扰。能否集中注意力解决关键问题、克制不断增加功能的冲动、不受关键人物或重要客户的影响,取决于产品经理是否有足够强的自律性——不但要遵守公司制度,还要严格要求自己。
几乎所有产品都有些不那么重要的功能——这些功能对提高销量和用户满意度毫无作用。如果去掉这些功能,产品甚至会因为简单、易用获得更多用户的喜爱。我建议过滤多余的功能,缩短研发时间,降低生产成本,让产品更早上市。
~~时间管理
电子邮件、即时消息和手机构成的世界充满了干扰。你可能一大早就来上班,拼命工作一整天,连吃饭喝水都顾不上,深夜回到家却发现到头来没完成一件重要工作。时间都用来“救火”和处理“紧急”事件了。
熟练、迅速地区分重要任务和紧急任务,合理地规划和安排时间是产品经理必备的技能。如果产品经理无法集中精力完成真正重要的任务,那产品就难免命运多舛了。
我认识太多每星期工作七十个小时、累得精疲力竭的产品经理。他们把所有的时间和精力都花在工作上,体力透支到了极限。对他们而言,最可怕的事实莫过于做的都是无用功。为此,我有意在培训课程中加入了时间管理和合理安排工作任务的内容。产品经理的时间应该用来改变现状,而不是疲于奔命参加大小会议、逐一回复邮件。有许多事情不值得做。
~~沟通技能
虽然沟通技巧可以学习,但要做到出类拔萃需要经年累月的练习。沟通(包括口头表达和书面表达)能力是产品经理必备的技能,如前所述,产品经理只能以理服人,绝不能靠职位压制他人。
口头表达能力可以在面试中测试,测试书面表达能力则需另寻他法。我常建议应聘者随身携带文字材料证明其书面表达能力,比如,不涉及专利的产品策划文档。
注意,如果应聘者使用非母语时带有口音或有轻微的语法错误,不代表其沟通技巧不佳,只要说话口齿清晰、易于理解、具有说服力即可,完美的发音和语法不是必要条件。
产品经理会花许多时间写电子邮件、产品说明文档、策划书、同类产品分析文档等。聪明的产品经理不会浪费时间写没人看的东西,一旦决定动笔就要做到最好,言之有物,让人信服。
书面表达务必条理清晰、言简意赅,因为同事(特别是公司高管)会根据这些文字评估产品经理的工作。有时文字材料是他们评判的唯一依据。
还有一种常见的沟通形式是演讲。对许多人来说,面对听众演讲并非易事,有效地表达观点更是困难。尽管如此,演讲是产品经理的家常便饭。产品经理必须用最短的时间向公司高管、大客户、销售团队解释产品的内涵和重要性。
我们都听过糟糕的演讲——幻灯片一张接一张没完没了,演讲人死板地朗诵条目,听众不得不费劲地揣摩每张图表的意义,既抓不住重点,也不明白价值何在。
与此相反,成功的产品经理尽可能减少幻灯片的页数,他们的演讲充满热情、重点清晰、数据充分、引人入胜,绝不超时(甚至提前结束)。他们更喜欢听众提问,即使遇到暂时无法回答的问题,也会努力尝试向提问者和听众阐述自己的理解。杰里·韦斯曼(Jerry
Weissman)的《演讲制胜:讲故事的艺术》是一本非常好的提高演讲水平的指南。
商业技能
作为产品团队的发言人,产品经理要协调团队与财务部门、营销部门、销售团队、公司高管之间的工作——必须使用这些人听得懂的概念和术语。
我认为产品经理应该具备双语技能。这并非指中文和英文,而是指产品经理既能与程序员讨论技术,又能与管理层和营销人员讨论成本结构、边际效应、市场份额、产品定位和品牌。
由于上述原因,很多产品经理都是商学院毕业的。企业需要懂得商务的人,所以雇用MBA。虽然MBA也可以成长为出色的产品经理,但总的来说商业技能只是产品经理需要具备的多种技能之一,而且完全可以在商学院以外的地方学到。比如,技术人员进入产品管理领域后,通过阅读、培训学习商业技能是很常见的事。
去哪里招聘产品经理?
具备以上这些素质和技能条件的人极少见,和优秀的产品一样稀少。没有比产品经理更重要的职位了,所以必须用严格的标准考察应聘者。
关于招聘产品经理,有许多不同的看法。许多公司认为他们需要的只是营销部门的人或有MBA学历的人,就像教科书对产品经理的定义一样。这种看法也许曾经是正确的,但如今无疑是一种谬论。
许多公司喜欢招聘从顶级商学院毕业、拥有技术类学士文凭、具有行业经验的MBA。不过别忘了MBA课程几乎不涉及产品管理。如果你认为现在的MBA毕业生们知道如何管理产品,那就大错特错了。
最有效的招聘途径是寻找具有上述特质潜力的人,通过培训课程和传帮带把他们训练成高素质的产品经理。这些人可能就藏身于公司内部。我认识许多优秀的产品经理,他们曾经是程序员、用户体验设计师、客服人员、技术支持人员、营销人员,甚至曾经是目标用户。他们利用各自的经验进一步完善产品管理工作。出于同样的原因,公司高管应该听取不同岗位员工对产品管理的建议。对于高管来说,这是宝贵的经验。
行业经验重要吗?
最近一位朋友向我了解一位产品经理应聘者(大卫)的情况,我曾经和大卫一起工作过。我的朋友是一家大众网络服务公司的主管,他非常喜欢大卫,但他心里有个疑问:“大卫是企业级软件产品方面的专家,他适合我们这种企业吗?”
我忍不住笑了,告诉他四年前我遇到过类似的问题。当时大卫现在的主管问我:“这个人对系统软件十分在行,可他能够做好企业级软件吗?”
其实大卫所受的教育与系统软件、企业级软件、大众网络服务都无关,甚至与软件技术无关。他是学金融出身的,非常聪明,善于快速进入新领域,理解新技术。
许多产品经理是因为他们的行业经验获聘的。经常有人问我产品经理是否必须具备领域和行业经验,我认为对某些产品来说,专业知识是必要的,比如,研发心脏除颤器,最好有一位懂得心脏护理的产品经理。但这只是个例,并非原则。
我甚至认为资深行业经验对产品经理的工作可能是不利的,因为长期从事某一行业的人通常会落入一种常见的心理陷阱:他们以为自己了解目标客户,盲目自信。产品经理应该习惯放下自己的成见。拥有资深行业经验的人也能做到这一点,但他们必须付出更多努力,保持开放的心态。
我并不是说管理产品不需要行业知识,相反,我觉得了解产品的领域知识(粗浅的了解不算数)是绝对必要的。我相信通过积极学习,高素质的产品经理可以快速熟悉新行业。以我自己为例,熟悉新行业达到自信制定产品策略的程度,只需要两三个月时间。
我相信开发企业级软件、系统软件、大众网络服务和消费类电子产品各自有不同的技能要求。例如,企业级软件的用户是数目较少的大企业(而不是数量上百万的消费者),所以有不同的手段了解需求、定义产品;不同类型产品的销售渠道各不相同;如果产品涉及硬件设备,则必须了解它会对流程和进度造成哪些影响;如果开发大众网络服务,必须知道如何展开规模管理和社区管理。
总的来说,我认为产品经理大约有80%的技能和天分可以用于不同类型的产品。
我并非要贬低经验的价值,但我发现最宝贵的经验不是行业知识或技术(这些都可能过时),而是打造优秀产品的流程、领导产品团队的能力、应对产品扩张的经验、个人对自己的认知,以及自我激励的能力。
与行业知识密切相关的是技术专长,业界一度非常看重两者的联系。有一次,我看到一家企业级软件公司招聘产品经理,要求应聘者具备开发Linux产品的经验。的确,不同操作系统之间差异很大,但产品经理如果连处理不同操作系统对产品影响的能力都不具备,那么等待他的麻烦将远比缺乏Linux知识来得多。
高科技产品行业虽然要求快速学习新技术,但更重要的是预见如何应用技术合理地解决问题。技术发展很快,所以产品经理必须善于快速学习新技术,解决新问题。我面试应聘者时,不关心他们已掌握的知识,只看重他们的学习思路。比如,让他们回忆研发产品之前,他们需要学习哪些知识,需要多长时间学习,如何利用这些知识。
年龄不是问题
各个年龄段都有出色的产品经理。为什么有人二十五岁就脱颖而出?首先,互联网真正普及是1995年以后的事情,因此,今天二十五岁左右的人和我们的上网经验一样多。互联网兴起时,十几岁的青少年很快学会了成年人搞不懂的技术。其次,经验虽然需要时间积累,但其他素质,比如智力和对产品的热情则与年龄无关。
当年为网景公司年轻的创始人马克•安德森(Marc
Andreessen)工作时,我不得不适应给这个二十出头的年轻人打工的事实。但是当我发现他吸收新技术和说服他人的能力后,我很快就忘记了他的年龄。未曾与他谋面的人会认为,拥有这种商业能力的人至少得年过四十。
寻找出色的产品经理不能以年龄、性别或种族作为判断标准。我知道行业中仍然存在不少偏见。例如,由于重视沟通技巧,我们尽量招聘母语是英语的应聘者。
我指出这一点并不是想谴责谁,只是想提醒大家,无意的偏见可能会让我们错过出色的产品经理。下次某个大学毕业生带着他的产品创意来找你时,你或许应该听一听,他的创意很可能是下一个Facebook。
出自:http://www.yixieshi.com/zhichang/8810.html
正常情况下开发人员使用已经定义好的API,这个过程叫Call。但是有时这样不能满足需求,就需要程序员注册自己的程序,然后让事先定义好多API在合适的时候调用注册的方法,这叫CallBack。
“当通常大家说的回调函数一般就是按照别人的定好的接口规范写的,等待别人调用的函数,在C语言中,回调函数通常通过函数指针来传递;在Java中,通常就是编写另外一个类或类库的人规定一个接口,然后你来实现这个接口,然后把这个实现类的一个对象作为参数传给别人的程序,别人的程序必要时就会通过那个接口来调用你编写的函数。”
使用技巧:定一个接口,在接口中声明我们想调用的方法。
在另一个方法中注册刚定义的回调接口
package com.call;
public interface Callback {
public void executeMethod();
}
-----------------------------------------------------
package com.call;
public class Tools {
public void getTime(Callback call) {
long start = System.currentTimeMillis();
call.executeMethod();
long end = System.currentTimeMillis();
System.out.println("cost time=" + (end - start));
}
}
---------------------------------------------
package com.call;
//测试执行方法消耗时间
public class Main {
public static void main(String[] args) {
Tools tool = new Tools();
tool.getTime(new Callback() {
public void executeMethod() {
new Main().testMethod();
}
});
}
public void testMethod() {
for (int i = 0; i < 10000; i++) {
System.out.print("");
}
}
}