UE4 Constructor Format & find Asset References &find Class Reference

UE构造器详解
本文深入探讨了Unreal Engine中UObject构造器的使用方法及原理,包括如何利用FObjectInitializer进行初始化,构造辅助器的使用,以及如何创建和查找组件等。

参见:https://docs.unrealengine.com/latest/CHN/Programming/UnrealArchitecture/Reference/Classes/index.html

The most basic form of a UObject constructor is shown below.

AMyClass::AMyClass(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
}

Obviously, this constructor does not perform any initialization. In fact, it has no effect on the object being created whatsoever. However, you will notice the FObjectInitializer parameter that is passed in to the constructor. This structure initializes the properties from an archetype or class default object (CDO) after the constructor returns. It is used to guarantee that every UObject that is constructed has the properties initialized. The FObjectInitializer can be used as demonstrated in the following constructor to skip any initialization of properties present in the constructor when they have already been set by an Archetype or CDO.

AUDKEmitterPool::AUDKEmitterPool(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    // Property initialization
    MaxActiveEffects = 200;
    SMC_MIC_ReductionTime = 2.0;
    IdealStaticMeshComponents = 200;
    IdealMaterialInstanceConstants = 200;
}

AUTDemoHUD::AUTDemoHUD(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
    , SomeNonProperty("Hi there")
{
    // Non-property initialization
    SomeOtherNonProperty = 26;

    // Property initialization
    SomeProperty = 30;
    SomeOtherProperty = "My message";
}
Asset References

Ideally asset references in classes do not exist. Hardcoded asset references are brittle and the movement has been toward using Blueprints for configuration of asset properties. However, this is fully supported. We do not want to search for assets every time we construct an object, so these searches are only done once. This is accomplished via a static struct which ensures that we do our asset searches only once:

ConstructorHelpers::FObjectFinder finds a reference to the specified UObject using StaticLoadObject. This is generally used to reference assets stored in content packages. Reports failure if the object is not found.

ATimelineTestActor::ATimelineTestActor(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    // Structure to hold one-time initialization
    struct FConstructorStatics
    {
        ConstructorHelpers::FObjectFinder<UStaticMesh> Object0;
        FConstructorStatics()
            : Object0(TEXT("StaticMesh'/Game/UT3/Pickups/Pickups/Health_Large/Mesh/S_Pickups_Base_Health_Large.S_Pickups_Base_Health_Large'"))
        {
        }
    };
    static FConstructorStatics ConstructorStatics;

    // Property initialization

    StaticMesh = ConstructorStatics.Object0.Object;
}
Class References

ConstructorHelpers::FClassFinder finds a reference to the specified UClass. Reports failure if the class is not found.

APylon::APylon(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    // Structure to hold one-time initialization
    struct FConstructorStatics
    {
        ConstructorHelpers::FClassFinder<UNavigationMeshBase> Class0;
        FConstructorStatics()
            : Class0(TEXT("class'Engine.NavigationMeshBase'"))
        {
        }
    };
    static FConstructorStatics ConstructorStatics;

    NavMeshClass = ConstructorStatics.Class0.Class;
}

In many cases, you can just use USomeClass::StaticClass() and skip the complexity of the ClassFinder altogether. For example, you can use the method below in most circumstances:

NavMeshClass = UNavigationMeshBase::StaticClass();

For cross-module references, it is probably better to use the ClassFinder method.

Names
APylon::APylon(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    // Structure to hold one-time initialization
    struct FConstructorStatics
    {
        FName NAME_Navigation;
        FConstructorStatics()
            : NAME_Navigation(TEXT("Navigation"))
        {
        }
    };
    static FConstructorStatics ConstructorStatics;

    SpriteCategoryName = ConstructorStatics.NAME_Navigation;
}
Components and Sub-Objects

Creating sub-objects, especially components, and modifying sub-objects belonging to parent classes also makes use of constructor helpers. The ConstructorHelpers::CreateComponent and ConstructorHelpers::FindComponent helpers can be used to create and find components, respectively.

AWindPointSource::AWindPointSource(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    // Structure to hold one-time initialization
    struct FConstructorStatics
    {
        FName NAME_Wind;
        FConstructorStatics()
            : NAME_Wind(TEXT("Wind"))
        {
        }
    };
    static FConstructorStatics ConstructorStatics;

    // Property initialization

    //Create a new component
    UWindPointSourceComponent* NewComponent0 = ConstructorHelpers::CreateComponent<UWindPointSourceComponent>(this, TEXT("WindPointSourceComponent0"));

    NewComponent0->PreviewRadiusComponent = NewComponent1;
    Component = NewComponent0;
    RootComponent = NewComponent0;

    //Create a new component
    UDrawSphereComponent* NewComponent1 = ConstructorHelpers::CreateComponent<UDrawSphereComponent>(this, TEXT("DrawSphereComponent0"));

    NewComponent1->ShapeColor.R = 173;
    NewComponent1->ShapeColor.G = 239;
    NewComponent1->ShapeColor.B = 231;
    NewComponent1->ShapeColor.A = 255;

    NewComponent1->AlwaysLoadOnClient = false;
    NewComponent1->AlwaysLoadOnServer = false;
    NewComponent1->bAbsoluteScale = true;
    NewComponent1->AttachParent = NewComponent0;

    //Find a component on the parent
    USpriteComponent* NewComponent2 = ConstructorHelpers::FindComponent<USpriteComponent>(this, TEXT("Sprite"));

    NewComponent2->SpriteCategoryName = ConstructorStatics.NAME_Wind;
    NewComponent2->AttachParent = NewComponent0;

    bNoDelete = true;
}
Array Manipulation

Arrays can be modified and manipulated using the standard methods belonging to the array.

 

ExampleArray.Add(NewComponent0);

In the event this is not desired, helper templates for adding items, expanding the array, and clearing the array are provided. For instance, to add a new component to the Components array, the following can be used.

int32 NewArrayIndex1 = ConstructorHelpers::AddArrayElement(ExampleArray);
ExampleArray(NewArrayIndex1) = NewComponent0;

 

转载于:https://www.cnblogs.com/pengyingh/articles/5481390.html

&lt;think&gt;好的,用户想了解JNI中的FindClass函数的参数类型及其用途。首先,我需要回忆一下JNI的基本知识。FindClass属于JNIEnv接口的一部分,主要用于从本地代码中获取Java类的引用。参数方面,我记得FindClass的参数是一个字符串,表示类的全限定名,比如&quot;java/lang/String&quot;。不过用户提到的问题可能还涉及其他方面,比如在不同线程中使用FindClass需要注意的问题,比如全局引用和局部引用的区别。 根据用户提供的引用内容,引用[1]提到在非静态方法调用时需要获取对象的类,而引用[2]讨论了多线程环境下FindClass的问题,指出需要将局部引用转换为全局引用以避免跨线程问题。这说明FindClass返回的是局部引用,如果在其他线程中使用,必须创建全局引用。 接下来,我需要详细说明FindClass的参数类型。FindClass的函数签名应该是jclass FindClass(JNIEnv *env, const char *name)。这里的name参数是UTF-8编码的字符串,表示类的全名,用斜杠代替包名中的点,例如&quot;com/example/MyClass&quot;。 还需要注意不同JNI版本中的差异,比如Android JNI中可能要求类名使用点分隔符,但标准JNI使用斜杠。这点可能需要特别指出,避免用户混淆。 另外,用户可能关心的点包括参数的正确格式、多线程中的处理方式、局部引用的生命周期管理,以及常见错误如类找不到的原因(类路径错误、未加载类等)。同时,示例代码可能有助于用户理解如何使用FindClass,比如正确转换类名格式,以及如何创建全局引用。 总结一下,回答的结构应该包括函数原型、参数说明、注意事项、示例代码和相关问题。需要确保覆盖参数类型、字符串格式、多线程注意事项和错误处理,同时引用提供的参考资料来支持这些点。&lt;/think&gt;### FindClass 参数类型及用途 在 JNI(Java Native Interface)中,`FindClass` 是用于从本地代码(如 C/C++)中获取 Java 类的引用的核心函数。以下是其参数类型及用途的详细说明: #### 1. 函数原型 ```c jclass FindClass(JNIEnv *env, const char *name); ``` - **参数 `env`**:JNI 环境指针,提供访问 JNI 功能的接口。 - **参数 `name`**:UTF-8 编码的字符串,表示目标类的**全限定名**,格式需符合 JNI 规范。 #### 2. 参数 `name` 的格式要求 - **类名转换规则**: - 包名中的点 `.` 需替换为斜杠 `/`。例如: Java 类 `java.lang.String` 对应参数为 `&quot;java/lang/String&quot;`。 - **数组类**需使用特殊符号: - 一维数组:`[Ljava/lang/String;`(对应 `String[]`) - 多维数组:`[[I`(对应 `int[][]`) - **Android 差异**: Android JNI 中,部分版本允许直接使用点分隔符(如 `&quot;java.lang.String&quot;`),但**建议遵循标准 JNI 格式**以提高兼容性[^1][^2]。 #### 3. 用途与注意事项 - **获取类引用**: 通过类名加载类,常用于调用静态方法、访问字段或构造对象。 - **多线程问题**: - `FindClass` 返回的是**局部引用**,仅在当前线程有效。 - 若需跨线程使用,需调用 `NewGlobalRef` 转换为全局引用,否则会因引用失效导致崩溃[^2]。 - 示例代码: ```c jclass localCls = env-&gt;FindClass(env, &quot;com/example/MyClass&quot;); jclass globalCls = (jclass)env-&gt;NewGlobalRef(env, localCls); ``` - **类加载失败原因**: - 类名格式错误(如未替换 `.` 为 `/`)。 - 类未在当前类加载器的上下文中加载(如动态生成的类)。 - 类路径(Classpath)未包含目标类。 #### 4. 典型应用场景 - **调用 Java 静态方法**: ```c jclass cls = env-&gt;FindClass(env, &quot;com/example/Utils&quot;); jmethodID method = env-&gt;GetStaticMethodID(env, cls, &quot;log&quot;, &quot;(Ljava/lang/String;)V&quot;); env-&gt;CallStaticVoidMethod(env, cls, method, env-&gt;NewStringUTF(env, &quot;Hello JNI&quot;)); ``` - **构造对象**: ```c jclass cls = env-&gt;FindClass(env, &quot;com/example/DataModel&quot;); jmethodID constructor = env-&gt;GetMethodID(env, cls, &quot;&lt;init&gt;&quot;, &quot;()V&quot;); jobject obj = env-&gt;NewObject(env, cls, constructor); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值